File size: 56,018 Bytes
ad05511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
/**
 * SarcoAdvisor-BSU 前端交互脚本
 * 处理用户输入、API调用和结果显示
 */

// 全局变量
let currentAssessment = null;
let currentLanguage = 'zh'; // 默认中文

// DOM加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
    console.log('SarcoAdvisor-BSU 前端已加载');
    
    // 初始化表单
    initializeForm();
    
    // 检查系统健康状态
    checkSystemHealth();
    
    // 添加输入验证
    addInputValidation();
    
    // 初始化语言
    initializeLanguage();
    
    // 初始化自动计算
    initializeAutoCalculation();
    
    // 初始化PAQ问卷逻辑
    initializePAQLogic();
});

/**
 * 初始化表单
 */
function initializeForm() {
    const form = document.getElementById('assessmentForm');
    const submitBtn = document.getElementById('submitBtn');
    
    // 添加表单提交事件监听
    form.addEventListener('submit', handleFormSubmit);
    
    // 添加实时验证
    const inputs = form.querySelectorAll('input[required], select[required]');
    inputs.forEach(input => {
        input.addEventListener('blur', validateInput);
        input.addEventListener('input', updateSubmitButton);
    });
    
    console.log('表单初始化完成');
}

/**
 * 检查系统健康状态
 */
async function checkSystemHealth() {
    try {
        const response = await fetch('/health');
        const health = await response.json();
        
        if (health.status === 'healthy') {
            console.log('系统状态正常:', health);
        } else {
            console.warn('系统状态异常:', health);
            const warningMsg = currentLanguage === 'zh' ?
                '系统部分功能可能不可用,但基础评估功能正常' :
                'Some system functions may be unavailable, but basic assessment functions are normal';
            showAlert(warningMsg, 'warning');
        }
    } catch (error) {
        console.error('健康检查失败:', error);
        const errorMsg = currentLanguage === 'zh' ?
            '无法连接到服务器,请稍后重试' :
            'Unable to connect to server, please try again later';
        showAlert(errorMsg, 'danger');
    }
}

/**
 * 处理表单提交
 */
async function handleFormSubmit(event) {
    event.preventDefault();
    
    console.log('开始处理表单提交');
    
    // 验证表单
    if (!validateForm()) {
        return;
    }
    
    // 收集表单数据
    const formData = collectFormData();
    
    // 显示加载状态
    showLoading();
    
    try {
        // 调用完整评估API
        const result = await performFullAssessment(formData);
        
        // 显示结果
        displayResults(result);
        
        // 保存当前评估
        currentAssessment = result;
        
    } catch (error) {
        console.error('评估失败:', error);
        hideLoading();
        
        // 显示详细错误信息
        let errorMessage = currentLanguage === 'zh' ? '评估过程中出现错误' : 'An error occurred during assessment';
        if (error.message) {
            errorMessage += currentLanguage === 'zh' ? ':' + error.message : ': ' + error.message;
        }
        errorMessage += currentLanguage === 'zh' ? '。请检查输入数据后重试。' : '. Please check your input data and try again.';
        
        showAlert(errorMessage, 'danger');
        
        // 同时在控制台输出用户数据用于调试
        console.error('失败的用户数据:', formData);
    }
}

/**
 * 验证表单
 */
function validateForm() {
    const form = document.getElementById('assessmentForm');
    const inputs = form.querySelectorAll('input[required], select[required]');
    let isValid = true;
    
    inputs.forEach(input => {
        if (!validateInput({ target: input })) {
            isValid = false;
        }
    });
    
    return isValid;
}

/**
 * 验证单个输入
 */
function validateInput(event) {
    const input = event.target;
    const value = input.value;
    const type = input.type;
    const min = parseFloat(input.min);
    const max = parseFloat(input.max);
    
    let isValid = true;
    let errorMessage = '';
    
    // 必填验证
    if (input.required && !value) {
        isValid = false;
        errorMessage = currentLanguage === 'zh' ? '此字段为必填项' : 'This field is required';
    }

    // 数值范围验证
    if (type === 'number' && value) {
        const numValue = parseFloat(value);
        if (isNaN(numValue)) {
            isValid = false;
            errorMessage = currentLanguage === 'zh' ? '请输入有效数字' : 'Please enter a valid number';
        } else if (!isNaN(min) && numValue < min) {
            isValid = false;
            errorMessage = currentLanguage === 'zh' ? `值不能小于 ${min}` : `Value cannot be less than ${min}`;
        } else if (!isNaN(max) && numValue > max) {
            isValid = false;
            errorMessage = currentLanguage === 'zh' ? `值不能大于 ${max}` : `Value cannot be greater than ${max}`;
        }
    }
    
    // 显示验证结果
    showInputValidation(input, isValid, errorMessage);
    
    return isValid;
}

/**
 * 显示输入验证结果
 */
function showInputValidation(input, isValid, errorMessage) {
    // 移除旧的验证状态
    input.classList.remove('is-valid', 'is-invalid');
    
    // 移除旧的错误信息
    const oldFeedback = input.parentNode.querySelector('.invalid-feedback');
    if (oldFeedback) {
        oldFeedback.remove();
    }
    
    if (!isValid && errorMessage) {
        // 添加错误状态
        input.classList.add('is-invalid');
        
        // 添加错误信息
        const feedback = document.createElement('div');
        feedback.className = 'invalid-feedback';
        feedback.textContent = errorMessage;
        input.parentNode.appendChild(feedback);
    } else if (input.value) {
        // 添加成功状态
        input.classList.add('is-valid');
    }
}

/**
 * 更新提交按钮状态
 */
function updateSubmitButton() {
    const form = document.getElementById('assessmentForm');
    const submitBtn = document.getElementById('submitBtn');
    const requiredInputs = form.querySelectorAll('input[required], select[required]');
    
    let allValid = true;
    requiredInputs.forEach(input => {
        if (!input.value || input.classList.contains('is-invalid')) {
            allValid = false;
        }
    });
    
    submitBtn.disabled = !allValid;
}

/**
 * 收集表单数据并计算衍生特征
 */
function collectFormData() {
    const rawData = {};
    const form = document.getElementById('assessmentForm');
    const formElements = form.elements;
    
    // 收集原始表单数据
    for (let element of formElements) {
        if (element.name) {
            let value = element.value;
            
            // 处理空值
            if (value === '' || value === null || value === undefined) {
                // 为必填字段提供默认值
                if (element.hasAttribute('required')) {
                    if (element.name === 'arthritis' || element.name === 'diabetes') {
                        value = '0'; // 默认无疾病史
                    } else if (element.type === 'select-one' && element.name.startsWith('PAQ')) {
                        value = '2'; // PAQ问题默认选择"否"
                    }
                }
            }
            
            if (value !== '' && value !== null && value !== undefined) {
                // 转换数字类型
                if (element.type === 'number') {
                    value = parseFloat(value);
                } else if (element.type === 'select-one') {
                    value = parseInt(value);
                }
                
                rawData[element.name] = value;
            }
        }
    }
    
    // 确保BMI和WWI有值(从自动计算获取)
    if (!rawData.body_mass_index) {
        const height = parseFloat(document.getElementById('height').value);
        const weight = parseFloat(document.getElementById('weight').value);
        if (height && weight) {
            const heightInMeters = height / 100;
            rawData.body_mass_index = parseFloat((weight / (heightInMeters * heightInMeters)).toFixed(1));
        }
    }
    
    if (!rawData.WWI) {
        const waist = parseFloat(document.getElementById('waist').value);
        const weight = parseFloat(document.getElementById('weight').value);
        if (waist && weight) {
            rawData.WWI = parseFloat((waist / Math.sqrt(weight)).toFixed(2));
        }
    }
    
    // 确保所有PAQ字段都有默认值(避免Pydantic验证错误)
    const requiredPAQFields = {
        // 必需的选择字段
        'PAQ605': 2, 'PAQ620': 2, 'PAQ635': 2, 'PAQ650': 2, 'PAQ665': 2,
        // 可选的天数字段(默认0)
        'PAQ610': 0, 'PAQ625': 0, 'PAQ640': 0, 'PAQ655': 0, 'PAQ670': 0,
        // 可选的时长字段(默认0)
        'PAD615': 0, 'PAD630': 0, 'PAD645': 0, 'PAD660': 0, 'PAD675': 0,
        // 久坐时间(默认8小时)
        'PAD680': 480,
        // 医疗史字段(默认否)
        'arthritis': 0, 'diabetes': 0
    };
    
    // 为缺失的字段设置默认值
    for (const [field, defaultValue] of Object.entries(requiredPAQFields)) {
        if (!(field in rawData)) {
            rawData[field] = defaultValue;
        }
    }
    
    // 使用PAD680作为sedentary_minutes
    rawData.sedentary_minutes = rawData.PAD680 || 480;
    
    // 计算衍生特征
    const derivedFeatures = calculateDerivedFeatures(rawData);
    
    // 合并原始数据和衍生特征
    const formData = { ...rawData, ...derivedFeatures };
    
    console.log('收集的表单数据(含默认值):', formData);
    return formData;
}

/**
 * 根据NHANES PAQ数据计算衍生特征
 * 完全按照create_pa_derived_features.py的逻辑实现
 */
function calculateDerivedFeatures(data) {
    const derived = {};
    
    // =====================================================
    // A. 活动总量/剂量特征 (Activity Volume/Dose)
    // =====================================================
    
    // A1. 每周总MET-分钟 (Total MET-minutes/week)
    const vigorousWorkMETs = 8.0 * (data.PAD615 || 0) * (data.PAQ610 || 0);
    const moderateWorkMETs = 4.0 * (data.PAD630 || 0) * (data.PAQ625 || 0);
    const transportationMETs = 4.0 * (data.PAD645 || 0) * (data.PAQ640 || 0);
    const vigorousRecMETs = 8.0 * (data.PAD660 || 0) * (data.PAQ655 || 0);
    const moderateRecMETs = 4.0 * (data.PAD675 || 0) * (data.PAQ670 || 0);
    
    const totalMETMinutesWeek = vigorousWorkMETs + moderateWorkMETs + transportationMETs + vigorousRecMETs + moderateRecMETs;
    
    // A2. 每周高强度活动总分钟数 (Total Vigorous Minutes/week)
    const vigorousWorkMins = (data.PAD615 || 0) * (data.PAQ610 || 0);
    const vigorousRecMins = (data.PAD660 || 0) * (data.PAQ655 || 0);
    const totalVigorousMinutesWeek = vigorousWorkMins + vigorousRecMins;
    
    // A3. 每周中等强度活动总分钟数 (Total Moderate Minutes/week)
    const moderateWorkMins = (data.PAD630 || 0) * (data.PAQ625 || 0);
    const transportationMins = (data.PAD645 || 0) * (data.PAQ640 || 0);
    const moderateRecMins = (data.PAD675 || 0) * (data.PAQ670 || 0);
    const totalModerateMinutesWeek = moderateWorkMins + transportationMins + moderateRecMins;
    
    // =====================================================
    // B. 活动模式/行为特征 (Activity Pattern/Behavior)  
    // =====================================================
    
    // B1. 平均每次高强度活动时长
    const totalVigorousDays = (data.PAQ610 || 0) + (data.PAQ655 || 0);
    const avgVigorousDurationPerBout = totalVigorousDays > 0 ? totalVigorousMinutesWeek / totalVigorousDays : 0;
    
    // B2. 平均每次中等强度活动时长
    const totalModerateDays = (data.PAQ625 || 0) + (data.PAQ640 || 0) + (data.PAQ670 || 0);
    const avgModerateDurationPerBout = totalModerateDays > 0 ? totalModerateMinutesWeek / totalModerateDays : 0;
    
    // B3. 活动多样性指数
    let activityDiversityIndex = 0;
    if ((data.PAQ605 || 0) > 0) activityDiversityIndex++; // 工作高强度
    if ((data.PAQ620 || 0) > 0) activityDiversityIndex++; // 工作中等强度
    if ((data.PAQ635 || 0) > 0) activityDiversityIndex++; // 交通活动
    if ((data.PAQ650 || 0) > 0) activityDiversityIndex++; // 休闲高强度
    if ((data.PAQ665 || 0) > 0) activityDiversityIndex++; // 休闲中等强度
    
    // =====================================================
    // C. 活动比例/构成特征 (Activity Ratio/Composition)
    // =====================================================
    
    // C1. 高强度活动MET-分钟占比
    const vigorousMETTotal = vigorousWorkMETs + vigorousRecMETs;
    const vigorousMETRatio = totalMETMinutesWeek > 0 ? vigorousMETTotal / totalMETMinutesWeek : 0;
    
    // C2. 活动/久坐比
    const totalActiveMinutesWeek = totalVigorousMinutesWeek + totalModerateMinutesWeek;
    const totalSedentaryMinutesWeek = (data.sedentary_minutes || data.PAD680 || 480) * 7; // 每日久坐 × 7天
    const activitySedentaryRatio = totalSedentaryMinutesWeek > 0 ? totalActiveMinutesWeek / totalSedentaryMinutesWeek : 0;
    
    // =====================================================
    // D. 指南达标特征 (Guideline Adherence)
    // =====================================================
    
    // D1. 每周中等强度等效总分钟数
    const totalModerateEquivalentMinutes = totalModerateMinutesWeek + (2 * totalVigorousMinutesWeek);
    
    // D2. 是否达到WHO体力活动推荐量
    const guidelineAdherenceBinary = totalModerateEquivalentMinutes >= 150 ? 1 : 0;
    
    // D3. 体力活动水平分级
    let activityLevelCategorical;
    if (totalModerateEquivalentMinutes >= 300) {
        activityLevelCategorical = 3; // 非常活跃
    } else if (totalModerateEquivalentMinutes >= 150) {
        activityLevelCategorical = 2; // 活跃
    } else if (totalModerateEquivalentMinutes > 0) {
        activityLevelCategorical = 1; // 低度活跃
    } else {
        activityLevelCategorical = 0; // 不活跃
    }
    
    // =====================================================
    // 整理最终衍生特征
    // =====================================================
    
    // A. 活动总量/剂量特征
    derived.Total_MET_minutes_week = parseFloat(totalMETMinutesWeek.toFixed(2));
    derived.Total_Vigorous_Minutes_week = parseFloat(totalVigorousMinutesWeek.toFixed(2));
    derived.Total_Moderate_Minutes_week = parseFloat(totalModerateMinutesWeek.toFixed(2));
    
    // B. 活动模式/行为特征
    derived.Avg_Vigorous_Duration_Per_Bout = parseFloat(avgVigorousDurationPerBout.toFixed(2));
    derived.Avg_Moderate_Duration_Per_Bout = parseFloat(avgModerateDurationPerBout.toFixed(2));
    derived.Activity_Diversity_Index = activityDiversityIndex;
    
    // C. 活动比例/构成特征
    derived.Vigorous_MET_Ratio = parseFloat(vigorousMETRatio.toFixed(3));
    derived.Activity_Sedentary_Ratio = parseFloat(activitySedentaryRatio.toFixed(3));
    
    // D. 指南达标特征
    derived.Total_Moderate_Equivalent_Minutes = parseFloat(totalModerateEquivalentMinutes.toFixed(2));
    derived.Guideline_Adherence_Binary = guidelineAdherenceBinary;
    derived.Activity_Level_Categorical = activityLevelCategorical;
    
    console.log('NHANES PAQ原始数据:', {
        PAQ610: data.PAQ610, PAD615: data.PAD615,
        PAQ625: data.PAQ625, PAD630: data.PAD630,
        PAQ640: data.PAQ640, PAD645: data.PAD645,
        PAQ655: data.PAQ655, PAD660: data.PAD660,
        PAQ670: data.PAQ670, PAD675: data.PAD675,
        PAD680: data.PAD680
    });
    console.log('计算的中间值:', {vigorousWorkMETs, moderateWorkMETs, transportationMETs, vigorousRecMETs, moderateRecMETs});
    console.log('计算的时间总量:', {totalVigorousMinutesWeek, totalModerateMinutesWeek, totalActiveMinutesWeek});
    console.log('最终衍生特征:', derived);
    
    return derived;
}

/**
 * 执行完整评估
 */
async function performFullAssessment(userData) {
    console.log('开始完整评估...');
    
    const response = await fetch('/api/full_assessment', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(userData)
    });
    
    if (!response.ok) {
        let errorMessage = `HTTP ${response.status}: `;
        try {
            const errorData = await response.json();
            console.error('服务器错误详情:', errorData);
            
            if (response.status === 422 && errorData.detail) {
                // 处理数据验证错误
                if (Array.isArray(errorData.detail)) {
                    const validationErrors = errorData.detail.map(err => 
                        `字段"${err.loc.join('.')}"错误: ${err.msg}`
                    ).join('; ');
                    errorMessage += validationErrors;
                } else {
                    errorMessage += JSON.stringify(errorData.detail);
                }
            } else {
                errorMessage += errorData.detail || JSON.stringify(errorData);
            }
        } catch (parseError) {
            errorMessage += response.statusText || '服务器错误';
        }
        throw new Error(errorMessage);
    }
    
    const result = await response.json();
    console.log('评估结果:', result);
    
    return result;
}

/**
 * 显示加载状态
 */
function showLoading() {
    document.getElementById('loadingSection').style.display = 'block';
    document.getElementById('resultsSection').style.display = 'none';
    
    // 滚动到加载区域
    document.getElementById('loadingSection').scrollIntoView({ 
        behavior: 'smooth' 
    });
}

/**
 * 隐藏加载状态
 */
function hideLoading() {
    document.getElementById('loadingSection').style.display = 'none';
}

/**
 * 显示评估结果
 */
function displayResults(assessment) {
    hideLoading();
    
    const resultsSection = document.getElementById('resultsSection');
    const resultsContent = document.getElementById('resultsContent');
    
    // 构建结果HTML
    const html = buildResultsHTML(assessment);
    resultsContent.innerHTML = html;
    
    // 显示结果区域
    resultsSection.style.display = 'block';
    resultsSection.classList.add('fade-in-up');
    
    // 滚动到结果区域
    resultsSection.scrollIntoView({ 
        behavior: 'smooth' 
    });
    
    console.log('结果显示完成');
}

/**
 * 构建结果HTML
 */
function buildResultsHTML(assessment) {
    const screening = assessment.screening;
    const advisory = assessment.advisory;
    const explanation = assessment.risk_explanation;

    let html = `
        <!-- 风险评估结果 -->
        <div class="row mb-4">
            <div class="col-12">
                <h4 class="text-primary mb-3">
                    <i class="fas fa-chart-pie me-2"></i>
                    <span class="lang-zh">风险评估结果</span>
                    <span class="lang-en" style="display: none;">Risk Assessment Results</span>
                </h4>
            </div>
        </div>

        <div class="row mb-4">
            <!-- 综合风险 -->
            <div class="col-md-12 mb-3">
                <div class="risk-level risk-${screening.overall_risk}">
                    <i class="fas fa-heartbeat fa-2x mb-2"></i>
                    <div>
                        <span class="lang-zh">综合风险评估: ${getRiskLevelText(screening.overall_risk)}</span>
                        <span class="lang-en" style="display: none;">Overall Risk Assessment: ${getRiskLevelText(screening.overall_risk, 'en')}</span>
                    </div>
                    <small>
                        <span class="lang-zh">系统置信度: ${(screening.confidence * 100).toFixed(1)}%</span>
                        <span class="lang-en" style="display: none;">System Confidence: ${(screening.confidence * 100).toFixed(1)}%</span>
                    </small>
                </div>
            </div>
        </div>

        <!-- 详细模型结果 -->
        <div class="row mb-4">
            <div class="col-12">
                <h5 class="text-secondary mb-3">
                    <i class="fas fa-chart-bar me-2"></i>
                    <span class="lang-zh">详细评估结果</span>
                    <span class="lang-en" style="display: none;">Detailed Assessment Results</span>
                </h5>
            </div>
        </div>

        <!-- 筛查模型结果 -->
        <div class="row mb-3">
            <div class="col-12">
                <h6 class="text-info">
                    <i class="fas fa-search me-1"></i>
                    <span class="lang-zh">筛查阶段 (高召回率 - 不漏诊)</span>
                    <span class="lang-en" style="display: none;">Screening Stage (High Recall - No Missed Diagnosis)</span>
                </h6>
            </div>
        </div>
        <div class="row mb-4">
            <!-- SarcoI筛查 -->
            <div class="col-md-6 mb-3">
                <div class="card border-info bg-light">
                    <div class="card-body text-center">
                        <div class="risk-level risk-${screening.sarcoI_risk} mb-2">
                            <i class="fas fa-user-injured fa-lg mb-1"></i>
                            <div>
                                <strong>
                                    <span class="lang-zh">SarcoI 筛查</span>
                                    <span class="lang-en" style="display: none;">SarcoI Screening</span>
                                </strong>
                            </div>
                            <div class="small">
                                <span class="lang-zh">RandomForest 模型</span>
                                <span class="lang-en" style="display: none;">RandomForest Model</span>
                            </div>
                        </div>
                        <div class="text-muted">
                            <div>
                                <span class="lang-zh">风险等级: <strong>${getRiskLevelText(screening.sarcoI_risk)}</strong></span>
                                <span class="lang-en" style="display: none;">Risk Level: <strong>${getRiskLevelText(screening.sarcoI_risk, 'en')}</strong></span>
                            </div>
                            <div>
                                <span class="lang-zh">肌少症特征相似度: <strong>${(screening.sarcoI_probability * 100).toFixed(1)}%</strong> (筛查阈值: 50%)</span>
                                <span class="lang-en" style="display: none;">Sarcopenia Feature Similarity: <strong>${(screening.sarcoI_probability * 100).toFixed(1)}%</strong> (Screening Threshold: 50%)</span>
                            </div>
                        </div>
                        <div class="mt-2 small text-info">
                            <div>Recall: <strong>91.14%</strong></div>
                            <div>Precision: <strong>43.05%</strong></div>
                        </div>
                    </div>
                </div>
            </div>

            <!-- SarcoII筛查 -->
            <div class="col-md-6 mb-3">
                <div class="card border-info bg-light">
                    <div class="card-body text-center">
                        <div class="risk-level risk-${screening.sarcoII_risk} mb-2">
                            <i class="fas fa-wheelchair fa-lg mb-1"></i>
                            <div>
                                <strong>
                                    <span class="lang-zh">SarcoII 筛查</span>
                                    <span class="lang-en" style="display: none;">SarcoII Screening</span>
                                </strong>
                            </div>
                            <div class="small">
                                <span class="lang-zh">CatBoost 模型</span>
                                <span class="lang-en" style="display: none;">CatBoost Model</span>
                            </div>
                        </div>
                        <div class="text-muted">
                            <div>
                                <span class="lang-zh">风险等级: <strong>${getRiskLevelText(screening.sarcoII_risk)}</strong></span>
                                <span class="lang-en" style="display: none;">Risk Level: <strong>${getRiskLevelText(screening.sarcoII_risk, 'en')}</strong></span>
                            </div>
                            <div>
                                <span class="lang-zh">肌少症特征相似度: <strong>${(screening.sarcoII_probability * 100).toFixed(1)}%</strong> (筛查阈值: 50%)</span>
                                <span class="lang-en" style="display: none;">Sarcopenia Feature Similarity: <strong>${(screening.sarcoII_probability * 100).toFixed(1)}%</strong> (Screening Threshold: 50%)</span>
                            </div>
                        </div>
                        <div class="mt-2 small text-info">
                            <div>Precision: <strong>25.48%</strong></div>
                            <div>Recall: <strong>89.83%</strong></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 建议模型结果 -->
        <!-- 建议模型部分 - 始终显示 -->
        <div class="row mb-3">
            <div class="col-12">
                <h6 class="text-success">
                    <i class="fas fa-lightbulb me-1"></i>
                    <span class="lang-zh">建议阶段 (高精确率 - 减少误诊)</span>
                    <span class="lang-en" style="display: none;">Advisory Stage (High Precision - Reduce Misdiagnosis)</span>
                </h6>
            </div>
        </div>
        <div class="row mb-4">
            <!-- SarcoI建议 -->
            <div class="col-md-6 mb-3">
                <div class="card border-success bg-light">
                    <div class="card-body text-center">
                        <div class="risk-level risk-${screening.sarcoI_advisory_risk} mb-2">
                            <i class="fas fa-user-injured fa-lg mb-1"></i>
                            <div>
                                <strong>
                                    <span class="lang-zh">SarcoI 建议</span>
                                    <span class="lang-en" style="display: none;">SarcoI Advisory</span>
                                </strong>
                            </div>
                            <div class="small">
                                <span class="lang-zh">CatBoost 模型</span>
                                <span class="lang-en" style="display: none;">CatBoost Model</span>
                            </div>
                        </div>
                        <div class="text-muted">
                            <div>
                                <span class="lang-zh">风险等级: <strong>${screening.sarcoI_advisory_risk ? getRiskLevelText(screening.sarcoI_advisory_risk) : '未评估'}</strong></span>
                                <span class="lang-en" style="display: none;">Risk Level: <strong>${screening.sarcoI_advisory_risk ? getRiskLevelText(screening.sarcoI_advisory_risk, 'en') : 'Not Assessed'}</strong></span>
                            </div>
                            <div>
                                <span class="lang-zh">肌少症特征相似度: <strong>${screening.sarcoI_advisory_probability ? (screening.sarcoI_advisory_probability * 100).toFixed(1) + '%' : 'N/A'}</strong> (建议阈值: 36%)</span>
                                <span class="lang-en" style="display: none;">Sarcopenia Feature Similarity: <strong>${screening.sarcoI_advisory_probability ? (screening.sarcoI_advisory_probability * 100).toFixed(1) + '%' : 'N/A'}</strong> (Advisory Threshold: 36%)</span>
                            </div>
                        </div>
                        <div class="mt-2 small text-success">
                            <div>
                                <span class="lang-zh">Precision: <strong>高精确率</strong></span>
                                <span class="lang-en" style="display: none;">Precision: <strong>High Precision</strong></span>
                            </div>
                            <div>
                                <span class="lang-zh">Recall: <strong>DiCE优化</strong></span>
                                <span class="lang-en" style="display: none;">Recall: <strong>DiCE Optimized</strong></span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <!-- SarcoII建议 -->
            <div class="col-md-6 mb-3">
                <div class="card border-success bg-light">
                    <div class="card-body text-center">
                        <div class="risk-level risk-${screening.sarcoII_advisory_risk} mb-2">
                            <i class="fas fa-wheelchair fa-lg mb-1"></i>
                            <div>
                                <strong>
                                    <span class="lang-zh">SarcoII 建议</span>
                                    <span class="lang-en" style="display: none;">SarcoII Advisory</span>
                                </strong>
                            </div>
                            <div class="small">
                                <span class="lang-zh">RandomForest 模型</span>
                                <span class="lang-en" style="display: none;">RandomForest Model</span>
                            </div>
                        </div>
                        <div class="text-muted">
                            <div>
                                <span class="lang-zh">风险等级: <strong>${screening.sarcoII_advisory_risk ? getRiskLevelText(screening.sarcoII_advisory_risk) : '未评估'}</strong></span>
                                <span class="lang-en" style="display: none;">Risk Level: <strong>${screening.sarcoII_advisory_risk ? getRiskLevelText(screening.sarcoII_advisory_risk, 'en') : 'Not Assessed'}</strong></span>
                            </div>
                            <div>
                                <span class="lang-zh">肌少症特征相似度: <strong>${screening.sarcoII_advisory_probability ? (screening.sarcoII_advisory_probability * 100).toFixed(1) + '%' : 'N/A'}</strong> (建议阈值: 52%)</span>
                                <span class="lang-en" style="display: none;">Sarcopenia Feature Similarity: <strong>${screening.sarcoII_advisory_probability ? (screening.sarcoII_advisory_probability * 100).toFixed(1) + '%' : 'N/A'}</strong> (Advisory Threshold: 52%)</span>
                            </div>
                        </div>
                        <div class="mt-2 small text-success">
                            <div>
                                <span class="lang-zh">Precision: <strong>高精确率</strong></span>
                                <span class="lang-en" style="display: none;">Precision: <strong>High Precision</strong></span>
                            </div>
                            <div>
                                <span class="lang-zh">Recall: <strong>DiCE优化</strong></span>
                                <span class="lang-en" style="display: none;">Recall: <strong>DiCE Optimized</strong></span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 风险解释 -->
        <div class="row mb-4">
            <div class="col-12">
                <div class="alert alert-info">
                    <h5 class="alert-heading">
                        <i class="fas fa-info-circle me-2"></i>${explanation.title}
                    </h5>
                    <p class="mb-2">${explanation.description}</p>
                    <hr>
                    <p class="mb-0">
                        <strong>
                            <span class="lang-zh">建议:</span>
                            <span class="lang-en" style="display: none;">Recommendation:</span>
                        </strong> ${explanation.recommendation}
                    </p>
                </div>
            </div>
        </div>
    `;

    // 如果有个性化建议,显示建议内容
    if (advisory && assessment.needs_advisory) {
        html += buildAdvisoryHTML(advisory);
    }

    // 添加处理时间信息
    html += `
        <div class="row mt-4">
            <div class="col-12">
                <small class="text-muted">
                    <i class="fas fa-clock me-1"></i>
                    <span class="lang-zh">评估耗时: ${assessment.total_processing_time.toFixed(2)} 秒</span>
                    <span class="lang-en" style="display: none;">Processing Time: ${assessment.total_processing_time.toFixed(2)} seconds</span>
                </small>
            </div>
        </div>
    `;

    return html;
}

/**
 * 构建建议HTML
 */
function buildAdvisoryHTML(advisory) {
    let html = `
        <div class="row mb-4">
            <div class="col-12">
                <h4 class="text-success mb-3">
                    <i class="fas fa-lightbulb me-2"></i>
                    <span class="lang-zh">个性化建议</span>
                    <span class="lang-en" style="display: none;">Personalized Recommendations</span>
                </h4>
            </div>
        </div>
    `;

    // 优先级行动
    if (advisory.priority_actions && advisory.priority_actions.length > 0) {
        html += `
            <div class="row mb-4">
                <div class="col-12">
                    <div class="alert alert-warning">
                        <h6 class="alert-heading">
                            <i class="fas fa-exclamation-triangle me-2"></i>
                            <span class="lang-zh">优先建议</span>
                            <span class="lang-en" style="display: none;">Priority Recommendations</span>
                        </h6>
                        <ul class="mb-0">
                            ${advisory.priority_actions.map(action => `<li>${action}</li>`).join('')}
                        </ul>
                    </div>
                </div>
            </div>
        `;
    }

    // SarcoI建议
    if (advisory.sarcoI_recommendations && advisory.sarcoI_recommendations.length > 0) {
        html += `
            <div class="row mb-3">
                <div class="col-12">
                    <h5 class="text-secondary">
                        <i class="fas fa-user-injured me-2"></i>
                        <span class="lang-zh">SarcoI相关建议</span>
                        <span class="lang-en" style="display: none;">SarcoI Related Recommendations</span>
                    </h5>
                </div>
            </div>
            <div class="row mb-4">
                ${advisory.sarcoI_recommendations.map(rec => buildRecommendationCard(rec)).join('')}
            </div>
        `;
    }

    // SarcoII建议
    if (advisory.sarcoII_recommendations && advisory.sarcoII_recommendations.length > 0) {
        html += `
            <div class="row mb-3">
                <div class="col-12">
                    <h5 class="text-secondary">
                        <i class="fas fa-wheelchair me-2"></i>
                        <span class="lang-zh">SarcoII相关建议</span>
                        <span class="lang-en" style="display: none;">SarcoII Related Recommendations</span>
                    </h5>
                </div>
            </div>
            <div class="row mb-4">
                ${advisory.sarcoII_recommendations.map(rec => buildRecommendationCard(rec)).join('')}
            </div>
        `;
    }

    // 目标指标
    if (advisory.target_metrics && Object.keys(advisory.target_metrics).length > 0) {
        html += `
            <div class="row mb-4">
                <div class="col-12">
                    <h5 class="text-secondary mb-3">
                        <i class="fas fa-target me-2"></i>
                        <span class="lang-zh">目标指标</span>
                        <span class="lang-en" style="display: none;">Target Metrics</span>
                    </h5>
                    <div class="row">
                        ${Object.entries(advisory.target_metrics).map(([key, value]) => `
                            <div class="col-md-6 mb-2">
                                <div class="d-flex justify-content-between">
                                    <span class="fw-bold">${key}:</span>
                                    <span class="text-primary">${value}</span>
                                </div>
                            </div>
                        `).join('')}
                    </div>
                </div>
            </div>
        `;
    }

    // 降级提示
    if (advisory.fallback_used) {
        html += `
            <div class="row mb-4">
                <div class="col-12">
                    <div class="alert alert-info">
                        <i class="fas fa-info-circle me-2"></i>
                        <span class="lang-zh">部分建议基于规则生成,建议咨询专业医生获取更详细的个性化指导。</span>
                        <span class="lang-en" style="display: none;">Some recommendations are rule-based. Please consult professional doctors for more detailed personalized guidance.</span>
                    </div>
                </div>
            </div>
        `;
    }

    return html;
}

/**
 * 构建单个建议卡片
 */
function buildRecommendationCard(recommendation) {
    // 获取优先级文本
    const getPriorityText = (priority, lang) => {
        const priorityTexts = {
            'zh': {
                'High': '高',
                'Medium': '中',
                'Low': '低'
            },
            'en': {
                'High': 'High',
                'Medium': 'Medium',
                'Low': 'Low'
            }
        };
        return priorityTexts[lang]?.[priority] || priority;
    };

    return `
        <div class="col-md-6 mb-3">
            <div class="recommendation-item">
                <div class="recommendation-title">
                    <i class="fas fa-arrow-right me-2 text-primary"></i>
                    ${recommendation.title}
                </div>
                <div class="recommendation-description">
                    ${recommendation.description}
                </div>
                ${recommendation.target_change ? `
                    <div class="text-muted small mb-2">
                        <i class="fas fa-target me-1"></i>
                        ${recommendation.target_change}
                    </div>
                ` : ''}
                <div class="recommendation-meta">
                    <span class="priority-badge priority-${recommendation.priority.toLowerCase()}">
                        <span class="lang-zh">${getPriorityText(recommendation.priority, 'zh')}优先级</span>
                        <span class="lang-en" style="display: none;">${getPriorityText(recommendation.priority, 'en')} Priority</span>
                    </span>
                    ${recommendation.expected_impact ? `
                        <small class="text-success">
                            <i class="fas fa-chart-line me-1"></i>
                            ${recommendation.expected_impact}
                        </small>
                    ` : ''}
                </div>
            </div>
        </div>
    `;
}

/**
 * 获取风险等级文本
 */
function getRiskLevelText(level, language = null) {
    const lang = language || currentLanguage;

    const levels = {
        'zh': {
            'low': '低风险',
            'medium': '中等风险',
            'high': '高风险'
        },
        'en': {
            'low': 'Low Risk',
            'medium': 'Medium Risk',
            'high': 'High Risk'
        }
    };

    return levels[lang]?.[level] || level;
}

/**
 * 显示警告信息
 */
function showAlert(message, type = 'info') {
    const alertHTML = `
        <div class="alert alert-${type} alert-dismissible fade show" role="alert">
            <i class="fas fa-${getAlertIcon(type)} me-2"></i>
            ${message}
            <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
        </div>
    `;

    // 在表单上方插入警告
    const form = document.getElementById('assessmentForm');
    const alertContainer = document.createElement('div');
    alertContainer.innerHTML = alertHTML;
    form.parentNode.insertBefore(alertContainer, form);

    // 5秒后自动关闭
    setTimeout(() => {
        const alert = alertContainer.querySelector('.alert');
        if (alert) {
            alert.remove();
        }
    }, 5000);
}

/**
 * 获取警告图标
 */
function getAlertIcon(type) {
    const icons = {
        'info': 'info-circle',
        'warning': 'exclamation-triangle',
        'danger': 'exclamation-circle',
        'success': 'check-circle'
    };
    return icons[type] || 'info-circle';
}

/**
 * 添加输入验证
 */
function addInputValidation() {
    // 身高合理性检查
    const heightInput = document.getElementById('height');
    if (heightInput) {
        heightInput.addEventListener('input', function() {
            const height = parseFloat(this.value);
            if (height && (height < 120 || height > 220)) {
                const message = currentLanguage === 'zh' ? '身高数值请确认是否正确' : 'Please confirm if height value is correct';
                showInputWarning(this, message);
            } else {
                hideInputWarning(this);
            }
        });
    }
    
    // 体重合理性检查
    const weightInput = document.getElementById('weight');
    if (weightInput) {
        weightInput.addEventListener('input', function() {
            const weight = parseFloat(this.value);
            if (weight && (weight < 35 || weight > 150)) {
                const message = currentLanguage === 'zh' ? '体重数值请确认是否正确' : 'Please confirm if weight value is correct';
                showInputWarning(this, message);
            } else {
                hideInputWarning(this);
            }
        });
    }
    
    // 腰围合理性检查
    const waistInput = document.getElementById('waist');
    if (waistInput) {
        waistInput.addEventListener('input', function() {
            const waist = parseFloat(this.value);
            if (waist && (waist < 60 || waist > 150)) {
                const message = currentLanguage === 'zh' ? '腰围数值请确认是否正确' : 'Please confirm if waist circumference is correct';
                showInputWarning(this, message);
            } else {
                hideInputWarning(this);
            }
        });
    }
    
    // 年龄合理性检查
    const ageInput = document.getElementById('age_years');
    if (ageInput) {
        ageInput.addEventListener('input', function() {
            const age = parseFloat(this.value);
            if (age && age > 80) {
                const message = currentLanguage === 'zh' ? '高龄用户建议咨询专业医生' : 'Elderly users are advised to consult professional doctors';
                showInputWarning(this, message);
            } else {
                hideInputWarning(this);
            }
        });
    }
}

/**
 * 显示输入警告
 */
function showInputWarning(input, message) {
    let warning = input.parentNode.querySelector('.input-warning');
    if (!warning) {
        warning = document.createElement('div');
        warning.className = 'input-warning text-warning small mt-1';
        input.parentNode.appendChild(warning);
    }
    warning.innerHTML = `<i class="fas fa-exclamation-triangle me-1"></i>${message}`;
}

/**
 * 隐藏输入警告
 */
function hideInputWarning(input) {
    const warning = input.parentNode.querySelector('.input-warning');
    if (warning) {
        warning.remove();
    }
}

/**
 * 导出评估结果 (未来功能)
 */
function exportResults() {
    if (!currentAssessment) {
        const noResultMsg = currentLanguage === 'zh' ?
            '没有可导出的评估结果' :
            'No assessment results to export';
        showAlert(noResultMsg, 'warning');
        return;
    }

    // TODO: 实现结果导出功能
    console.log('导出评估结果:', currentAssessment);
    const devMsg = currentLanguage === 'zh' ?
        '导出功能正在开发中' :
        'Export function is under development';
    showAlert(devMsg, 'info');
}

/**
 * 初始化语言设置
 */
function initializeLanguage() {
    // 从localStorage读取语言设置
    const savedLang = localStorage.getItem('sarco-language');
    if (savedLang) {
        currentLanguage = savedLang;
        if (currentLanguage === 'en') {
            switchToEnglish();
        }
    }
}

/**
 * 切换语言
 */
function toggleLanguage() {
    if (currentLanguage === 'zh') {
        switchToEnglish();
    } else {
        switchToChinese();
    }
}

/**
 * 切换到英文
 */
function switchToEnglish() {
    currentLanguage = 'en';
    document.querySelectorAll('.lang-zh').forEach(el => el.style.display = 'none');
    document.querySelectorAll('.lang-en').forEach(el => el.style.display = 'inline');
    document.getElementById('langToggleText').textContent = '中文';
    document.documentElement.lang = 'en';
    document.title = 'SarcoAdvisor-BSU - Sarcopenia Risk Assessment System';

    // 更新select选项
    updateSelectOptions('en');

    // 如果有已显示的结果,重新渲染
    if (currentAssessment) {
        displayResults(currentAssessment);
    }

    // 保存设置
    localStorage.setItem('sarco-language', 'en');
}

/**
 * 切换到中文
 */
function switchToChinese() {
    currentLanguage = 'zh';
    document.querySelectorAll('.lang-en').forEach(el => el.style.display = 'none');
    document.querySelectorAll('.lang-zh').forEach(el => el.style.display = 'inline');
    document.getElementById('langToggleText').textContent = 'English';
    document.documentElement.lang = 'zh-CN';
    document.title = 'SarcoAdvisor-BSU - 肌少症风险评估系统';

    // 更新select选项
    updateSelectOptions('zh');

    // 如果有已显示的结果,重新渲染
    if (currentAssessment) {
        displayResults(currentAssessment);
    }

    // 保存设置
    localStorage.setItem('sarco-language', 'zh');
}

/**
 * 更新select选项的显示
 */
function updateSelectOptions(lang) {
    const select = document.getElementById('race_ethnicity');
    const options = select.querySelectorAll('option');
    
    options.forEach(option => {
        if (option.value === '') {
            option.textContent = lang === 'zh' ? '请选择' : 'Please select';
        } else if (option.value === '0') {
            option.textContent = lang === 'zh' ? '美洲原住民' : 'Native American';
        } else if (option.value === '1') {
            option.textContent = lang === 'zh' ? '亚洲人' : 'Asian';
        } else if (option.value === '2') {
            option.textContent = lang === 'zh' ? '非洲裔美国人' : 'African American';
        } else if (option.value === '3') {
            option.textContent = lang === 'zh' ? '西班牙裔' : 'Hispanic';
        } else if (option.value === '4') {
            option.textContent = lang === 'zh' ? '白人' : 'White';
        }
    });
}

/**
 * 初始化自动计算功能
 */
function initializeAutoCalculation() {
    // 获取输入元素
    const heightInput = document.getElementById('height');
    const weightInput = document.getElementById('weight');
    const waistInput = document.getElementById('waist');
    const bmiInput = document.getElementById('body_mass_index');
    const wwiInput = document.getElementById('WWI');
    
    // 添加事件监听器
    if (heightInput && weightInput && waistInput) {
        heightInput.addEventListener('input', calculateBMIAndWWI);
        weightInput.addEventListener('input', calculateBMIAndWWI);
        waistInput.addEventListener('input', calculateBMIAndWWI);
        
        console.log('自动计算功能已初始化');
    } else {
        console.warn('未找到身体测量输入字段');
    }
}

/**
 * 计算BMI和WWI
 */
function calculateBMIAndWWI() {
    const height = parseFloat(document.getElementById('height').value);
    const weight = parseFloat(document.getElementById('weight').value);
    const waist = parseFloat(document.getElementById('waist').value);
    
    const bmiInput = document.getElementById('body_mass_index');
    const wwiInput = document.getElementById('WWI');
    
    // 计算BMI
    if (height && weight && height > 0) {
        const heightInMeters = height / 100; // 转换为米
        const bmi = weight / (heightInMeters * heightInMeters);
        bmiInput.value = bmi.toFixed(1);
        
        // 添加BMI颜色指示
        updateBMIStatus(bmi);
    } else {
        bmiInput.value = '';
        bmiInput.className = 'form-control bg-light';
    }
    
    // 计算WWI
    if (waist && weight && weight > 0) {
        const wwi = waist / Math.sqrt(weight);
        wwiInput.value = wwi.toFixed(2);
        
        // 添加WWI颜色指示
        updateWWIStatus(wwi);
    } else {
        wwiInput.value = '';
        wwiInput.className = 'form-control bg-light';
    }
    
    // 触发表单验证更新
    updateSubmitButton();
}

/**
 * 更新BMI状态指示
 */
function updateBMIStatus(bmi) {
    const bmiInput = document.getElementById('body_mass_index');
    
    // 移除旧的状态类
    bmiInput.className = 'form-control bg-light';
    
    if (bmi < 18.5) {
        bmiInput.classList.add('border-info'); // 偏瘦
    } else if (bmi >= 18.5 && bmi < 24) {
        bmiInput.classList.add('border-success'); // 正常
    } else if (bmi >= 24 && bmi < 28) {
        bmiInput.classList.add('border-warning'); // 超重
    } else if (bmi >= 28) {
        bmiInput.classList.add('border-danger'); // 肥胖
    }
}

/**
 * 更新WWI状态指示
 */
function updateWWIStatus(wwi) {
    const wwiInput = document.getElementById('WWI');
    
    // 移除旧的状态类
    wwiInput.className = 'form-control bg-light';
    
    // WWI正常范围大约在9-12之间
    if (wwi < 9) {
        wwiInput.classList.add('border-info'); // 较低
    } else if (wwi >= 9 && wwi <= 12) {
        wwiInput.classList.add('border-success'); // 正常
    } else if (wwi > 12 && wwi <= 14) {
        wwiInput.classList.add('border-warning'); // 较高
    } else if (wwi > 14) {
        wwiInput.classList.add('border-danger'); // 很高
    }
}

/**
 * 初始化PAQ问卷条件显示逻辑
 */
function initializePAQLogic() {
    // 工作高强度活动条件显示
    const paq605 = document.getElementById('PAQ605');
    const vigorousWorkDetails = document.getElementById('vigorous_work_details');
    
    if (paq605 && vigorousWorkDetails) {
        paq605.addEventListener('change', function() {
            if (this.value === '1') {
                vigorousWorkDetails.style.display = 'block';
                document.getElementById('PAQ610').required = true;
                document.getElementById('PAD615').required = true;
            } else {
                vigorousWorkDetails.style.display = 'none';
                document.getElementById('PAQ610').required = false;
                document.getElementById('PAD615').required = false;
                document.getElementById('PAQ610').value = '';
                document.getElementById('PAD615').value = '';
            }
        });
    }
    
    // 工作中等强度活动条件显示
    const paq620 = document.getElementById('PAQ620');
    const moderateWorkDetails = document.getElementById('moderate_work_details');
    
    if (paq620 && moderateWorkDetails) {
        paq620.addEventListener('change', function() {
            if (this.value === '1') {
                moderateWorkDetails.style.display = 'block';
                document.getElementById('PAQ625').required = true;
                document.getElementById('PAD630').required = true;
            } else {
                moderateWorkDetails.style.display = 'none';
                document.getElementById('PAQ625').required = false;
                document.getElementById('PAD630').required = false;
                document.getElementById('PAQ625').value = '';
                document.getElementById('PAD630').value = '';
            }
        });
    }
    
    // 交通活动条件显示
    const paq635 = document.getElementById('PAQ635');
    const transportDetails = document.getElementById('transport_details');
    
    if (paq635 && transportDetails) {
        paq635.addEventListener('change', function() {
            if (this.value === '1') {
                transportDetails.style.display = 'block';
                document.getElementById('PAQ640').required = true;
                document.getElementById('PAD645').required = true;
            } else {
                transportDetails.style.display = 'none';
                document.getElementById('PAQ640').required = false;
                document.getElementById('PAD645').required = false;
                document.getElementById('PAQ640').value = '';
                document.getElementById('PAD645').value = '';
            }
        });
    }
    
    // 休闲高强度活动条件显示
    const paq650 = document.getElementById('PAQ650');
    const vigorousRecDetails = document.getElementById('vigorous_rec_details');
    
    if (paq650 && vigorousRecDetails) {
        paq650.addEventListener('change', function() {
            if (this.value === '1') {
                vigorousRecDetails.style.display = 'block';
                document.getElementById('PAQ655').required = true;
                document.getElementById('PAD660').required = true;
            } else {
                vigorousRecDetails.style.display = 'none';
                document.getElementById('PAQ655').required = false;
                document.getElementById('PAD660').required = false;
                document.getElementById('PAQ655').value = '';
                document.getElementById('PAD660').value = '';
            }
        });
    }
    
    // 休闲中等强度活动条件显示
    const paq665 = document.getElementById('PAQ665');
    const moderateRecDetails = document.getElementById('moderate_rec_details');
    
    if (paq665 && moderateRecDetails) {
        paq665.addEventListener('change', function() {
            if (this.value === '1') {
                moderateRecDetails.style.display = 'block';
                document.getElementById('PAQ670').required = true;
                document.getElementById('PAD675').required = true;
            } else {
                moderateRecDetails.style.display = 'none';
                document.getElementById('PAQ670').required = false;
                document.getElementById('PAD675').required = false;
                document.getElementById('PAQ670').value = '';
                document.getElementById('PAD675').value = '';
            }
        });
    }
    
    console.log('PAQ问卷条件显示逻辑已初始化');
}

// 导出到全局作用域
window.SarcoAdvisor = {
    exportResults,
    showAlert,
    getCurrentAssessment: () => currentAssessment,
    toggleLanguage
};