瀏覽代碼

feat: 添加能力对比和整体报表页面,优化数据展示逻辑

refactor(workProfile): 简化部门查找逻辑,移除递归实现
refactor(home-new): 调整数据展示逻辑,优化角色权限处理
style: 移除无用代码和注释,保持代码整洁
huoyi 2 月之前
父節點
當前提交
1cf49959ed

+ 12 - 0
src/pages.json

@@ -45,6 +45,18 @@
45 45
       }
46 46
     },
47 47
     {
48
+      "path": "pages/capabilityComparison/index",
49
+      "style": {
50
+        "navigationBarTitleText": "能力对比"
51
+      }
52
+    },
53
+    {
54
+      "path": "pages/statisticalReport/index",
55
+      "style": {
56
+        "navigationBarTitleText": "整体报表"
57
+      }
58
+    },
59
+    {
48 60
       "path": "pages/mine/avatar/index",
49 61
       "style": {
50 62
         "navigationBarTitleText": "修改头像"

File diff suppressed because it is too large
+ 1460 - 0
src/pages/capabilityComparison/index.vue


+ 0 - 0
src/pages/capabilityComparison/能力对比


+ 0 - 15
src/pages/home-new/components/type-detail.vue

@@ -69,21 +69,6 @@
69 69
 
70 70
                 <!-- test角色特殊显示:主管合格率排行和班组合格率排行 -->
71 71
                 <div class="rank-section" v-if="role && (role.includes('test') || role.includes('zhijianke'))">
72
-                    <!-- 大队合格率排行 -->
73
-                    <div class="rank-title">{{ item.title === '查获上报' ? '大队查获总数排名' : item.title == '抽问抽答' ? '大队正确率排名' :
74
-                        '大队合格率排名' }}
75
-                    </div>
76
-                    <div v-for="(dept, i) in (item.brigadeRank || [])" :key="'dept-' + i" class="rank-item">
77
-                        <div class="rank-label">{{ dept.name }}</div>
78
-                        <div class="rank-progress">
79
-                            <h-rank-line
80
-                                :percentage="item.title !== '查获上报' ? Number(dept.passRate || 0) : getPercentage(dept.passRate, item.departmentRank)"
81
-                                endType="round" :height="10" :color="['#F9CA91', '#ED9E3E']">
82
-                                <div class="rank-info"><span style="color: #999999">{{ dept.passRate || 0 }}</span>
83
-                                </div>
84
-                            </h-rank-line>
85
-                        </div>
86
-                    </div>
87 72
                     <!-- 主管合格率排行 -->
88 73
                     <div class="rank-header">
89 74
                         <div class="rank-title">{{ item.title === '查获上报' ? '主管查获总数排名' : item.title == '抽问抽答' ? '主管正确率排名'

+ 46 - 50
src/pages/home-new/index.vue

@@ -177,7 +177,7 @@ export default {
177 177
         },
178 178
         // TypeDetail组件数据
179 179
         typeDetailData() {
180
-            console.log('this.seizeData', this.seizeData)
180
+            console.log('this.seizeData', this.seizeData,this.seizeData.stationMasterData)
181 181
             return [
182 182
                 {
183 183
                     title: '查获上报',
@@ -186,14 +186,13 @@ export default {
186 186
                     statTitle: '查获数量',
187 187
                     teamSortType: this.sortStates['查获上报'].teamSortType,
188 188
                     deptSortType: this.sortStates['查获上报'].deptSortType,
189
-
190
-                    dividerIndex: this.role.includes('kezhang') ? 1 : 0,
189
+                    dividerIndex: this.isBrigade ? 1 : 0,
191 190
                     dataItems: this.getSeizeDataItems(),
192 191
                     rankList: this.getSeizeRankList(),
193
-                    departmentRank: this.seizeData.stationMasterData && this.seizeData.stationMasterData.departmentRankings.map(item => ({ ...item, passRate: item.seizureCount.toFixed(2), name: item.departmentName })),
194
-                    bottomDepartmentRank: this.seizeData.stationMasterData && this.seizeData.stationMasterData.departmentRankings && [...this.seizeData.stationMasterData.departmentRankings].sort((a, b) => (a.seizureCount || 0) - (b.seizureCount || 0)).slice(0, 5).map(item => ({ ...item, passRate: item.seizureCount.toFixed(2), name: item.departmentName })),
195
-                    teamRank: this.seizeData.stationMasterData && this.seizeData.stationMasterData.topFiveTeamRankings.map(item => ({ ...item, passRate: item.seizureCount.toFixed(2), name: item.teamName })),
196
-                    bottomTeamRank: this.seizeData.stationMasterData && this.seizeData.stationMasterData.botomFiveTeamRankings.map(item => ({ ...item, passRate: item.seizureCount.toFixed(2), name: item.teamName })),
192
+                    departmentRank: this.seizeData.stationMasterData && this.seizeData.stationMasterData.topThreeDepartmentRankings ? this.seizeData.stationMasterData.topThreeDepartmentRankings.map(item => ({ ...item, passRate: item.seizureCount.toFixed(2), name: item.departmentName })) : [],
193
+                    bottomDepartmentRank: this.seizeData.stationMasterData && this.seizeData.stationMasterData.botomThreeDepartmentRankings && this.seizeData.stationMasterData.departmentRankings ? [...this.seizeData.stationMasterData.departmentRankings].sort((a, b) => (a.seizureCount || 0) - (b.seizureCount || 0)).slice(0, 3).map(item => ({ ...item, passRate: item.seizureCount.toFixed(2), name: item.departmentName })) : [],
194
+                    teamRank: this.seizeData.stationMasterData && this.seizeData.stationMasterData.topThreeTeamRankings ? this.seizeData.stationMasterData.topThreeTeamRankings.map(item => ({ ...item, passRate: item.seizureCount.toFixed(2), name: item.teamName })) : [],
195
+                    bottomTeamRank: this.seizeData.stationMasterData && this.seizeData.stationMasterData.botomThreeTeamRankings ? this.seizeData.stationMasterData.botomThreeTeamRankings.map(item => ({ ...item, passRate: item.seizureCount.toFixed(2), name: item.teamName })) : [],
197 196
                 },
198 197
                 {
199 198
                     title: '抽问抽答',
@@ -202,8 +201,7 @@ export default {
202 201
                     statTitle: '正确率(%)',
203 202
                     teamSortType: this.sortStates['抽问抽答'].teamSortType,
204 203
                     deptSortType: this.sortStates['抽问抽答'].deptSortType,
205
-
206
-                    dividerIndex: this.role.includes('kezhang') ? 1 : 0,
204
+                    dividerIndex: this.isBrigade ? 1 : 0,
207 205
                     dataItems: this.getQuestionDataItems(),
208 206
                     rankList: this.getQuestionRankList(),
209 207
                     departmentRank: this.accuracyStatistics.topDepts && this.accuracyStatistics.topDepts.map(item => ({ ...item, passRate: item.accuracy.toFixed(2), name: item.deptName })),
@@ -218,14 +216,13 @@ export default {
218 216
                     statTitle: '合格率(%)',
219 217
                     teamSortType: this.sortStates['巡检'].teamSortType,
220 218
                     deptSortType: this.sortStates['巡检'].deptSortType,
221
-
222
-                    dividerIndex: this.role.includes('kezhang') ? 1 : 0,
219
+                    dividerIndex: this.isBrigade ? 1 : 0,
223 220
                     dataItems: this.getInspectionDataItems(),
224 221
                     completed: this.inspectionData.doneNumber,
225 222
                     pending: this.inspectionData.doingNumber,
226 223
                     rankList: this.getRankList(),
227 224
                     departmentRank: this.inspectionData.departmentRankingList && this.inspectionData.departmentRankingList.map(item => ({ ...item, passRate: (item.passRate * 100).toFixed(2) })),
228
-                    bottomDepartmentRank: this.inspectionData.departmentRankingList && [...this.inspectionData.departmentRankingList].sort((a, b) => (a.passRate || 0) - (b.passRate || 0)).slice(0, 5).map(item => ({ ...item, passRate: (item.passRate * 100).toFixed(2) })),
225
+                    bottomDepartmentRank: this.inspectionData.reverseDepartmentRankingList && [...this.inspectionData.reverseDepartmentRankingList].sort((a, b) => (a.passRate || 0) - (b.passRate || 0)).slice(0, 5).map(item => ({ ...item, passRate: (item.passRate * 100).toFixed(2) })),
229 226
                     teamRank: this.inspectionData.teamRankingList && this.inspectionData.teamRankingList.map(item => ({ ...item, passRate: (item.passRate * 100).toFixed(2) })),
230 227
                     bottomTeamRank: this.inspectionData.reverseTeamRankingList && this.inspectionData.reverseTeamRankingList.map(item => ({ ...item, passRate: (item.passRate * 100).toFixed(2) })),
231 228
                 }
@@ -257,7 +254,7 @@ export default {
257 254
         attendanceItems() {
258 255
             let res = {};
259 256
 
260
-            if (this.role.includes('kezhang') || this.isZhanZhang) {
257
+            if (this.role.includes('kezhang') || this.isZhanZhang || this.isBrigade) {
261 258
                 // 班组长选择班组视图
262 259
                 if (this.isZhanZhang) {
263 260
                     res = this.attendanceStats.stationLeaderStats
@@ -834,7 +831,7 @@ export default {
834 831
 
835 832
         // 根据角色获取巡检数据项数组
836 833
         getInspectionDataItems() {
837
-            const { personalPassRate, teamPassRate, departmentPassRate, stationPassRate, teamRankingList, departmentRankingList,brigadeRankingList,brigadePassRate } = this.inspectionData;
834
+            const { personalPassRate, teamPassRate, departmentPassRate, stationPassRate, teamRankingList, departmentRankingList, brigadeRankingList, brigadePassRate } = this.inspectionData;
838 835
             if (this.isIndividualView) {
839 836
                 // SecurityCheck角色:本人、班平均、主管平均、站平均
840 837
                 return [
@@ -849,33 +846,33 @@ export default {
849 846
                 return [
850 847
                     { label: '班组', value: ((teamPassRate || 0) * 100).toFixed(2), isImage: false },
851 848
                     { label: '主管平均', value: ((departmentPassRate || 0) * 100).toFixed(2), isImage: false, color: departmentPassRate < teamPassRate ? '#00AE41' : '#F96060' },
849
+                    { label: '大队平均', value: ((brigadePassRate || 0) * 100).toFixed(2), isImage: false, color: brigadePassRate < personalPassRate ? '#00AE41' : '#F96060' },
852 850
                     { label: '站平均', value: ((stationPassRate || 0) * 100).toFixed(2), isImage: false, color: stationPassRate < teamPassRate ? '#00AE41' : '#F96060' }
853 851
                 ];
854 852
             } else if (this.role.includes('kezhang')) {
855 853
                 // kezhang角色:主管、站平均、前三名班组(isImage: true)
856 854
                 return [
857 855
                     { label: '主管', value: ((departmentPassRate || 0) * 100).toFixed(2), isImage: false },
856
+                    { label: '大队平均', value: ((brigadePassRate || 0) * 100).toFixed(2), isImage: false, color: brigadePassRate < personalPassRate ? '#00AE41' : '#F96060' },
858 857
                     { label: '站平均', value: ((stationPassRate || 0) * 100).toFixed(2), isImage: false, color: stationPassRate < departmentPassRate ? '#00AE41' : '#F96060' },
859
-                    { label: this.getObjByRank(teamRankingList, 1).name, value: '/static/images/icon/one.png', isImage: true },
860
-                    { label: this.getObjByRank(teamRankingList, 2).name, value: '/static/images/icon/two.png', isImage: true },
861
-                    { label: this.getObjByRank(teamRankingList, 3).name, value: '/static/images/icon/three.png', isImage: true }
858
+
862 859
                 ];
863 860
             } else if (this.isBrigade) {
864 861
                 // brigade角色:主管、站平均、前三名班组(isImage: true)
865 862
                 return [
866
-                    { label: '主管', value: ((departmentPassRate || 0) * 100).toFixed(2), isImage: false },
867
-                    { label: '大队平均', value: ((brigadePassRate || 0) * 100).toFixed(2), isImage: false, color: brigadePassRate < departmentPassRate ? '#00AE41' : '#F96060' },
868
-                    { label: this.getObjByRank(teamRankingList, 1).name, value: '/static/images/icon/one.png', isImage: true },
869
-                    { label: this.getObjByRank(teamRankingList, 2).name, value: '/static/images/icon/two.png', isImage: true },
870
-                    { label: this.getObjByRank(teamRankingList, 3).name, value: '/static/images/icon/three.png', isImage: true }
863
+                    { label: '大队', value: ((brigadePassRate || 0) * 100).toFixed(2), isImage: false },
864
+                    { label: '站平均', value: ((stationPassRate || 0) * 100).toFixed(2), isImage: false, color: stationPassRate < brigadePassRate ? '#00AE41' : '#F96060' },
865
+                    { label: this.getObjByRank(departmentRankingList, 1).name, value: '/static/images/icon/one.png', isImage: true },
866
+                    { label: this.getObjByRank(departmentRankingList, 2).name, value: '/static/images/icon/two.png', isImage: true },
867
+                    { label: this.getObjByRank(departmentRankingList, 3).name, value: '/static/images/icon/three.png', isImage: true }
871 868
                 ];
872 869
             } else if (this.isZhanZhang) {
873 870
                 // test/zhijianke角色:全站、前三名的科室(isImage: true)
874 871
                 return [
875 872
                     { label: '全站', value: ((stationPassRate || 0) * 100).toFixed(2), isImage: false },
876
-                    { label: this.getObjByRank(departmentRankingList, 1).name, value: '/static/images/icon/one.png', isImage: true },
877
-                    { label: this.getObjByRank(departmentRankingList, 2).name, value: '/static/images/icon/two.png', isImage: true },
878
-                    { label: this.getObjByRank(departmentRankingList, 3).name, value: '/static/images/icon/three.png', isImage: true }
873
+                    { label: this.getObjByRank(brigadeRankingList, 1).name, value: '/static/images/icon/one.png', isImage: true },
874
+                    { label: this.getObjByRank(brigadeRankingList, 2).name, value: '/static/images/icon/two.png', isImage: true },
875
+                    { label: this.getObjByRank(brigadeRankingList, 3).name, value: '/static/images/icon/three.png', isImage: true }
879 876
                 ];
880 877
             } else {
881 878
                 // 默认角色:检查项、完成率
@@ -923,6 +920,7 @@ export default {
923 920
                     { label: this.getObjByRank(topTeamsInDept, 3).teamName, value: '/static/images/icon/three.png', isImage: true }
924 921
                 ];
925 922
             } else if (this.isZhanZhang) {
923
+                
926 924
                 // test/zhijianke角色:全站、前三名的科室(isImage: true)
927 925
                 return [
928 926
                     { label: '全站', value: (siteAvgAccuracy || 0), isImage: false },
@@ -940,8 +938,6 @@ export default {
940 938
         },
941 939
         //根据角色获取查获数据项目组
942 940
         getSeizeDataItems() {
943
-
944
-
945 941
             if (this.isIndividualView) {
946 942
                 // SecurityCheck角色:从securityCheckerData解构
947 943
                 const { securityCheckerData } = this.seizeData;
@@ -969,50 +965,49 @@ export default {
969 965
             } else if (this.role.includes('kezhang')) {
970 966
                 // kezhang角色:从securityCheckerData解构
971 967
                 const { sectionMasterData } = this.seizeData;
972
-                const { teamAverage, brigadeAverage, departmentAverage,stationAverage } = sectionMasterData || {}
968
+                const { brigadeAverage, departmentAverage, stationAverage } = sectionMasterData || {}
973 969
 
974 970
                 // kezhang角色:主管、站平均、前三名班组(isImage: true)
975 971
                 return [
976 972
                     { label: '主管', value: departmentAverage || 0, isImage: false },
977
-                    { label: '主管平均', value: departmentAverage || 0, isImage: false, color: departmentAverage < teamAverage ? '#00AE41' : '#F96060' },
978
-                    { label: '大队平均', value: brigadeAverage || 0, isImage: false, color: brigadeAverage < teamAverage ? '#00AE41' : '#F96060' },
979
-                    { label: '站平均', value: (stationAverage && stationAverage.toFixed(2)) || 0, isImage: false, color: stationAverage < teamAverage ? '#00AE41' : '#F96060' }
973
+                    { label: '大队平均', value: brigadeAverage || 0, isImage: false, color: brigadeAverage < departmentAverage ? '#00AE41' : '#F96060' },
974
+                    { label: '站平均', value: (stationAverage && stationAverage.toFixed(2)) || 0, isImage: false, color: stationAverage < departmentAverage ? '#00AE41' : '#F96060' }
980 975
                     // { label: this.getObjByRank(topThreeTeams, 1).teamName, value: '/static/images/icon/one.png', isImage: true },
981 976
                     // { label: this.getObjByRank(topThreeTeams, 2).teamName, value: '/static/images/icon/two.png', isImage: true },
982 977
                     // { label: this.getObjByRank(topThreeTeams, 3).teamName, value: '/static/images/icon/three.png', isImage: true }
983 978
                 ];
984 979
             } else if (this.isBrigade) {
985 980
                 // brigade角色:从securityCheckerData解构
986
-                const { sectionMasterData } = this.seizeData;
987
-                const { stationAverage, topThreeTeams, departmentAverage } = sectionMasterData || {}
981
+                const { brigadeMasterData } = this.seizeData;
982
+                const { stationAverage, topThreeDepartment, brigadeAverage } = brigadeMasterData || {}
988 983
 
989 984
                 // brigade角色:主管、站平均、前三名班组(isImage: true)
990 985
                 return [
991
-                    { label: '主管', value: departmentAverage || 0, isImage: false },
992
-                    { label: '大队平均', value: stationAverage?.toFixed(2) || 0, isImage: false, color: stationAverage?.toFixed(2) < departmentAverage ? '#00AE41' : '#F96060' },
993
-                    { label: this.getObjByRank(topThreeTeams, 1).teamName, value: '/static/images/icon/one.png', isImage: true },
994
-                    { label: this.getObjByRank(topThreeTeams, 2).teamName, value: '/static/images/icon/two.png', isImage: true },
995
-                    { label: this.getObjByRank(topThreeTeams, 3).teamName, value: '/static/images/icon/three.png', isImage: true }
986
+                    { label: '大队', value: brigadeAverage || 0, isImage: false },
987
+                    { label: '站平均', value: (stationAverage && stationAverage.toFixed(2)) || 0, isImage: false, color: stationAverage < brigadeAverage ? '#00AE41' : '#F96060' },
988
+                    { label: this.getObjByRank(topThreeDepartment, 1).departmentName, value: '/static/images/icon/one.png', isImage: true },
989
+                    { label: this.getObjByRank(topThreeDepartment, 2).departmentName, value: '/static/images/icon/two.png', isImage: true },
990
+                    { label: this.getObjByRank(topThreeDepartment, 3).departmentName, value: '/static/images/icon/three.png', isImage: true }
996 991
                 ];
997 992
             } else if (this.isZhanZhang) {
998 993
                 // test/zhijianke角色:从securityCheckerData解构
999 994
                 const { stationMasterData } = this.seizeData;
1000
-                const { totalStationSeizure, departmentRankings } = stationMasterData || {}
995
+                const { totalStationSeizure, brigadeRankings } = stationMasterData || {}
1001 996
 
1002 997
                 // 对departmentRankings数组按照seizureCount由大到小排序
1003
-                const sortedDepartmentRankings = Array.isArray(departmentRankings)
1004
-                    ? [...departmentRankings].sort((a, b) => (b.seizureCount || 0) - (a.seizureCount || 0))
998
+                const sortedBrigadeRankings = Array.isArray(brigadeRankings)
999
+                    ? [...brigadeRankings].sort((a, b) => (b.seizureCount || 0) - (a.seizureCount || 0))
1005 1000
                     : [];
1006 1001
 
1007
-                if (sortedDepartmentRankings.length == 0) {
1002
+                if (sortedBrigadeRankings.length == 0) {
1008 1003
                     return []
1009 1004
                 }
1010 1005
                 // test/zhijianke角色:全站、前三名的科室(isImage: true)
1011 1006
                 return [
1012 1007
                     { label: '全站', value: totalStationSeizure || 0, isImage: false },
1013
-                    { label: sortedDepartmentRankings[0].departmentName, value: '/static/images/icon/one.png', isImage: true },
1014
-                    { label: sortedDepartmentRankings[1].departmentName, value: '/static/images/icon/two.png', isImage: true },
1015
-                    { label: sortedDepartmentRankings[2].departmentName, value: '/static/images/icon/three.png', isImage: true }
1008
+                    { label: sortedBrigadeRankings[0].brigadeName, value: '/static/images/icon/one.png', isImage: true },
1009
+                    { label: sortedBrigadeRankings[1].brigadeName, value: '/static/images/icon/two.png', isImage: true },
1010
+                    { label: sortedBrigadeRankings[2].brigadeName, value: '/static/images/icon/three.png', isImage: true }
1016 1011
                 ];
1017 1012
             } else {
1018 1013
                 // 默认角色:检查项、完成率
@@ -1030,7 +1025,7 @@ export default {
1030 1025
 
1031 1026
         // 根据角色获取巡检排名列表
1032 1027
         getRankList() {
1033
-            const { teamRanking, teamTotal, departmentRanking, departmentTotal, stationRanking, stationTotal,brigadeTotal,brigadeRanking } = this.inspectionData;
1028
+            const { teamRanking, teamTotal, departmentRanking, departmentTotal, stationRanking, stationTotal, brigadeTotal, brigadeRanking } = this.inspectionData;
1034 1029
             // 根据角色返回不同的排名数据
1035 1030
             if (this.isIndividualView) {
1036 1031
                 // 科长、SecurityCheck角色:显示班组、科级和站级排名
@@ -1042,11 +1037,12 @@ export default {
1042 1037
                 ];
1043 1038
             } else if (this.role.includes('kezhang')) {
1044 1039
                 return [
1040
+                    { label: '大队排名', current: departmentRanking || 0, total: departmentTotal || 0, percentage: departmentTotal ? ((departmentRanking || 0) / departmentTotal) * 100 : 0 },
1045 1041
                     { label: '站级排名', current: stationRanking || 0, total: stationTotal || 0, percentage: stationTotal ? ((stationRanking || 0) / stationTotal) * 100 : 0, type: 'station' }
1046 1042
                 ];
1047 1043
             } else if (this.isBrigade) {
1048 1044
                 return [
1049
-                    { label: '大队排名', current: departmentRanking || 0, total: departmentTotal || 0, percentage: departmentTotal ? ((departmentRanking || 0) / departmentTotal) * 100 : 0 },
1045
+                   
1050 1046
                     { label: '站级排名', current: stationRanking || 0, total: stationTotal || 0, percentage: stationTotal ? ((stationRanking || 0) / stationTotal) * 100 : 0, type: 'station' }
1051 1047
                 ];
1052 1048
             } else if (this.isTeamView) {
@@ -1102,7 +1098,7 @@ export default {
1102 1098
             // 根据角色返回不同的排名数据
1103 1099
             if (this.isIndividualView) {
1104 1100
                 const { securityCheckerData } = this.seizeData;
1105
-                const { teamRanking, departmentRanking, stationRanking,brigadeRanking } = securityCheckerData || {}
1101
+                const { teamRanking, departmentRanking, stationRanking, brigadeRanking } = securityCheckerData || {}
1106 1102
                 // 科长、SecurityCheck角色:显示班组、科级和站级排名
1107 1103
                 return [
1108 1104
                     { label: '班组排名', current: teamRanking?.currentRank || 0, total: teamRanking?.totalItems || 0, percentage: teamRanking?.totalItems ? ((teamRanking.currentRank || 0) / teamRanking.totalItems) * 100 : 0 },
@@ -1112,7 +1108,7 @@ export default {
1112 1108
                 ];
1113 1109
             } else if (this.role.includes('kezhang')) {
1114 1110
                 const { sectionMasterData } = this.seizeData;
1115
-                const { stationRanking, departmentRanking,brigadeRanking } = sectionMasterData || {};
1111
+                const { stationRanking, departmentRanking, brigadeRanking } = sectionMasterData || {};
1116 1112
                 // 科长、SecurityCheck角色:显示班组、科级和站级排名
1117 1113
                 return [
1118 1114
                     { label: '大队排名', current: brigadeRanking?.currentRank || 0, total: brigadeRanking?.totalItems || 0, percentage: brigadeRanking?.totalItems ? ((brigadeRanking.currentRank || 0) / brigadeRanking.totalItems) * 100 : 0 },
@@ -1128,7 +1124,7 @@ export default {
1128 1124
                 ];
1129 1125
             } else if (this.isTeamView) {
1130 1126
                 const { teamLeaderData } = this.seizeData;
1131
-                const { departmentRanking, stationRanking,brigadeRanking } = teamLeaderData || {}
1127
+                const { departmentRanking, stationRanking, brigadeRanking } = teamLeaderData || {}
1132 1128
                 // 班组长角色:显示科级和站级排名
1133 1129
                 return [
1134 1130
                     { label: '主管排名', current: departmentRanking?.currentRank || 0, total: departmentRanking?.totalItems || 0, percentage: departmentRanking?.totalItems ? ((departmentRanking.currentRank || 0) / departmentRanking.totalItems) * 100 : 0 },

+ 307 - 0
src/pages/statisticalReport/index.vue

@@ -0,0 +1,307 @@
1
+<template>
2
+  <HomeContainer>
3
+    <!-- 时间范围显示 -->
4
+    <!-- <view v-if="startDate && endDate" class="time-range-display">
5
+      <text class="time-range-text">时间范围:{{ startDate }} 至 {{ endDate }}</text>
6
+    </view> -->
7
+
8
+    <!-- 统计表格区域 -->
9
+    <view class="statistic-tables-section">
10
+      <!-- 查获数量统计表格 -->
11
+      <StatisticTable title="查获数量" :columns="seizureColumns" :data="seizureTableData" :blankData="'0'"
12
+        class="statistic-table" />
13
+
14
+      <!-- 在岗时长统计表格 -->
15
+      <StatisticTable title="在岗时长" :columns="workingColumns" :data="workingTableData" :blankData="'0'"
16
+        class="statistic-table" />
17
+
18
+      <!-- 巡检合格率统计表格 -->
19
+      <StatisticTable title="巡检合格率" :columns="inspectionColumns" :data="inspectionTableData" :blankData="'0'"
20
+        class="statistic-table" />
21
+
22
+      <!-- 抽问抽答正确率统计表格 -->
23
+      <StatisticTable title="抽问抽答正确率" :columns="questionColumns" :data="questionTableData" :blankData="'0'"
24
+        class="statistic-table" />
25
+
26
+      <!-- 培训答题分数统计表格 -->
27
+      <StatisticTable title="培训答题分数" :columns="learningColumns" :data="learningTableData" :blankData="'0'"
28
+        class="statistic-table" />
29
+    </view>
30
+  </HomeContainer>
31
+</template>
32
+
33
+<script>
34
+import HomeContainer from '@/components/HomeContainer.vue'
35
+import HeadTitle from '@/components/HeadTitle.vue'
36
+import StatisticTable from '@/components/statistic-table/statistic-table.vue'
37
+import { getHomeReportWhole } from '@/api/home-new/home-new.js'
38
+export default {
39
+  name: 'StatisticalReport',
40
+  components: {
41
+    HomeContainer,
42
+    HeadTitle,
43
+    StatisticTable
44
+  },
45
+  data() {
46
+    return {
47
+      // 时间参数
48
+      startDate: '',
49
+      endDate: '',
50
+      // 表格列配置
51
+      seizureColumns: [
52
+        { props: 'name', title: '查获数量' },
53
+        { props: 'totalNumber', title: '总数' },
54
+        { props: 'averageNumber', title: '平均数' },
55
+        { props: 'medianNumber', title: '中位数' },
56
+        { props: 'maxNumber', title: '最大值' },
57
+        { props: 'minNumber', title: '最小值' }
58
+      ],
59
+      workingColumns: [
60
+        { props: 'name', title: '在岗时长' },
61
+        { props: 'totalNumber', title: '总数' },
62
+        { props: 'averageNumber', title: '平均数' },
63
+        { props: 'medianNumber', title: '中位数' },
64
+        { props: 'maxNumber', title: '最大值' },
65
+        { props: 'minNumber', title: '最小值' }
66
+      ],
67
+      inspectionColumns: [
68
+        { props: 'name', title: '巡检合格率(%)' },
69
+        // { props: 'totalNumber', title: '总数' },
70
+        { props: 'averageNumber', title: '平均数' },
71
+        { props: 'medianNumber', title: '中位数' },
72
+        { props: 'maxNumber', title: '最大值' },
73
+        { props: 'minNumber', title: '最小值' }
74
+      ],
75
+      questionColumns: [
76
+        { props: 'name', title: '抽问抽答正确率(%)' },
77
+        // { props: 'totalNumber', title: '总数' },
78
+        { props: 'averageNumber', title: '平均数' },
79
+        { props: 'medianNumber', title: '中位数' },
80
+        { props: 'maxNumber', title: '最大值' },
81
+        { props: 'minNumber', title: '最小值' }
82
+      ],
83
+      learningColumns: [
84
+        { props: 'name', title: '培训答题分数' },
85
+        // { props: 'totalNumber', title: '总数' },
86
+        { props: 'averageNumber', title: '平均数' },
87
+        { props: 'medianNumber', title: '中位数' },
88
+        { props: 'maxNumber', title: '最大值' },
89
+        { props: 'minNumber', title: '最小值' }
90
+      ],
91
+      // 统计表格数据
92
+      seizureTableData: [],      // 查获数量 - seizureList
93
+      workingTableData: [],      // 在岗时长 - workingList
94
+      inspectionTableData: [],   // 巡检合格率 - checkList
95
+      questionTableData: [],     // 抽问抽答正确率 - answerList
96
+      learningTableData: []      // 培训答题分数 - learningList
97
+    }
98
+  },
99
+
100
+  async onLoad(options) {
101
+    // 接收页面参数
102
+    this.startDate = options.startDate || ''
103
+    this.endDate = options.endDate || ''
104
+
105
+    console.log('接收到的时间参数:', {
106
+      startDate: this.startDate,
107
+      endDate: this.endDate
108
+    })
109
+
110
+    // 页面加载时获取数据
111
+    await this.loadData()
112
+  },
113
+
114
+  methods: {
115
+    // 加载数据方法
116
+    async loadData() {
117
+      try {
118
+        // 根据时间参数构建查询条件
119
+        const queryParams = {}
120
+        if (this.startDate && this.endDate) {
121
+          queryParams.startDate = this.startDate
122
+          queryParams.endDate = this.endDate
123
+        }
124
+
125
+        console.log('加载数据的查询参数:', queryParams)
126
+
127
+        // 调用getHomeReportWhole接口获取真实数据
128
+        const response = await getHomeReportWhole(queryParams)
129
+
130
+        if (response.code === 200 && response.data) {
131
+          // 处理接口返回的真实数据
132
+          const { checkList, learningList, seizureList, workingList, answerList } = response.data;
133
+
134
+          // 分配数据到对应的表格
135
+          this.seizureTableData = seizureList || this.generateMockDepartmentData('查获数量')
136
+          this.workingTableData = workingList || this.generateMockDepartmentData('在岗时长')
137
+          this.inspectionTableData = checkList.map((item) => {
138
+            return {
139
+              ...item,
140
+              medianNumber: `${(item.medianNumber * 100).toFixed(2)}`,
141
+              maxNumber: `${(item.maxNumber * 100).toFixed(2)}`,
142
+              minNumber: `${(item.minNumber * 100).toFixed(2)}`,
143
+              averageNumber: `${(item.averageNumber * 100).toFixed(2)}`
144
+            }
145
+          }) || this.generateMockDepartmentData('巡检合格率')
146
+          this.questionTableData = answerList.map((item) => {
147
+            return {
148
+              ...item,
149
+              medianNumber: `${(item.medianNumber).toFixed(2)}`,
150
+              maxNumber: `${(item.maxNumber).toFixed(2)}`,
151
+              minNumber: `${(item.minNumber).toFixed(2)}`,
152
+              averageNumber: `${(item.averageNumber).toFixed(2)}`
153
+            }
154
+          }) || this.generateMockDepartmentData('抽问抽答正确率')
155
+          this.learningTableData = learningList || this.generateMockDepartmentData('培训答题分数')
156
+
157
+          // 如果有时间参数,显示时间范围提示
158
+          // if (this.startDate && this.endDate) {
159
+          //   uni.showToast({
160
+          //     title: `已加载 ${this.startDate} 至 ${this.endDate} 的数据`,
161
+          //     icon: 'none',
162
+          //     duration: 2000
163
+          //   })
164
+          // }
165
+        } else {
166
+          // 如果接口返回失败,使用模拟数据
167
+          console.warn('接口返回数据异常,使用模拟数据')
168
+          this.seizureTableData = this.generateMockDepartmentData('查获数量')
169
+          this.workingTableData = this.generateMockDepartmentData('在岗时长')
170
+          this.inspectionTableData = this.generateMockDepartmentData('巡检合格率')
171
+          this.questionTableData = this.generateMockDepartmentData('抽问抽答正确率')
172
+          this.learningTableData = this.generateMockDepartmentData('培训答题分数')
173
+        }
174
+      } catch (error) {
175
+        console.error('加载数据失败:', error)
176
+        // 如果接口调用失败,使用模拟数据
177
+        this.seizureTableData = this.generateMockDepartmentData('查获数量')
178
+        this.workingTableData = this.generateMockDepartmentData('在岗时长')
179
+        this.inspectionTableData = this.generateMockDepartmentData('巡检合格率')
180
+        this.questionTableData = this.generateMockDepartmentData('抽问抽答正确率')
181
+        this.learningTableData = this.generateMockDepartmentData('培训答题分数')
182
+
183
+        uni.showToast({
184
+          title: '数据加载失败,使用模拟数据',
185
+          icon: 'none'
186
+        })
187
+      }
188
+    },
189
+
190
+
191
+
192
+
193
+
194
+    // 生成模拟科室数据(根据类型生成不同科室的统计数据)
195
+    generateMockDepartmentData(type) {
196
+      // 模拟科室列表
197
+      const departments = ['安检一科', '安检二科', '安检三科', '安检四科', '安检五科']
198
+
199
+      // 根据类型设置基础数值范围
200
+      const baseConfig = {
201
+        '查获数量': { baseTotal: 800, baseAvg: 20, baseMedian: 18, baseMax: 40, baseMin: 5 },
202
+        '在岗时长': { baseTotal: 1200, baseAvg: 30, baseMedian: 28, baseMax: 60, baseMin: 15 },
203
+        '巡检合格率': { baseTotal: 1000, baseAvg: 25, baseMedian: 23, baseMax: 50, baseMin: 10 },
204
+        '抽问抽答正确率': { baseTotal: 600, baseAvg: 15, baseMedian: 14, baseMax: 30, baseMin: 3 },
205
+        '培训答题分数': { baseTotal: 900, baseAvg: 22, baseMedian: 21, baseMax: 45, baseMin: 8 }
206
+      }
207
+
208
+      const config = baseConfig[type] || baseConfig['查获数量']
209
+
210
+      return departments.map((dept, index) => {
211
+        // 为每个科室生成略有差异的数据
212
+        const variation = (index + 1) * 0.1 // 每个科室数据略有不同
213
+
214
+        return {
215
+          name: dept,
216
+          totalNumber: Math.round(config.baseTotal * (1 + variation * 0.2)),
217
+          averageNumber: (config.baseAvg * (1 + variation * 0.1)).toFixed(1),
218
+          medianNumber: (config.baseMedian * (1 + variation * 0.1)).toFixed(1),
219
+          maxNumber: Math.round(config.baseMax * (1 + variation * 0.3)),
220
+          minNumber: Math.round(config.baseMin * (1 + variation * 0.1))
221
+        }
222
+      })
223
+    },
224
+
225
+    // 生成模拟表格数据(根据时间参数调整数据)
226
+    generateMockTableData(type, queryParams = {}) {
227
+      // 根据时间范围调整数据值
228
+      let baseValue = 1000
229
+      let completionRate = 98.5
230
+      let passRate = 96.2
231
+      let avgTime = 15
232
+
233
+      // 如果有时间参数,根据时间范围调整数据
234
+      if (queryParams.startDate && queryParams.endDate) {
235
+        // 计算时间跨度(天数)
236
+        const start = new Date(queryParams.startDate)
237
+        const end = new Date(queryParams.endDate)
238
+        const diffTime = Math.abs(end - start)
239
+        const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
240
+
241
+        // 根据时间跨度调整数据
242
+        baseValue = Math.round(1000 * (diffDays / 30)) // 假设30天为基准
243
+        completionRate = 98.5 - (30 - Math.min(diffDays, 30)) * 0.1
244
+        passRate = 96.2 - (30 - Math.min(diffDays, 30)) * 0.05
245
+        avgTime = 15 + (30 - Math.min(diffDays, 30)) * 0.2
246
+      }
247
+
248
+      return [
249
+        { label: `${type}总数`, value: baseValue.toLocaleString() },
250
+        { label: `${type}完成率`, value: `${completionRate.toFixed(1)}%` },
251
+        { label: `${type}合格率`, value: `${passRate.toFixed(1)}%` },
252
+        { label: `${type}平均用时`, value: `${avgTime.toFixed(0)}分钟` }
253
+      ]
254
+    }
255
+  }
256
+}
257
+</script>
258
+
259
+<style lang="scss" scoped>
260
+.statistical-report {
261
+  min-height: 100vh;
262
+  background-color: #f5f7fa;
263
+}
264
+
265
+// 时间范围显示样式
266
+.time-range-display {
267
+  background-color: #ffffff;
268
+  padding: 24rpx 32rpx;
269
+  margin-bottom: 24rpx;
270
+  border-radius: 12rpx;
271
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
272
+
273
+  .time-range-text {
274
+    font-size: 28rpx;
275
+    color: #666;
276
+    font-weight: 500;
277
+  }
278
+}
279
+
280
+.page-header {
281
+  margin-bottom: 32rpx;
282
+}
283
+
284
+.statistic-tables-section {
285
+  .statistic-table {
286
+    margin-bottom: 32rpx;
287
+  }
288
+}
289
+
290
+// 响应式适配
291
+@media (max-width: 750px) {
292
+  .time-range-display {
293
+    padding: 20rpx 24rpx;
294
+    margin-bottom: 20rpx;
295
+
296
+    .time-range-text {
297
+      font-size: 26rpx;
298
+    }
299
+  }
300
+
301
+  .statistic-tables-section {
302
+    .statistic-table {
303
+      margin-bottom: 24rpx;
304
+    }
305
+  }
306
+}
307
+</style>

+ 7 - 31
src/pages/workProfile/index.vue

@@ -165,29 +165,9 @@ export default {
165 165
         handleLevelChange(value) {
166 166
             console.log("value===", value, this.levelOptions)
167 167
             let targetObj = {}
168
-            // 递归查找函数
169
-            const findInTree = (items, id) => {
170
-                for (let item of items) {
171
-                    if (item.id == id) {
172
-                        return item;
173
-                    }
174
-                    if (item.children && item.children.length > 0) {
175
-                        const found = findInTree(item.children, id);
176
-                        if (found) return found;
177
-                    }
178
-                }
179
-                return null;
180
-            };
181
-
182
-            targetObj = findInTree(this.levelOptions, value);
183
-            if (!targetObj) {
184
-                console.warn('未找到匹配的部门对象,id:', value);
185
-                return;
186
-            }
187
-            console.log("targetObj===", targetObj)
188
-
189
-            this.selectedLevelId = targetObj.id;
190
-            this.selectedLevelType = targetObj.deptType == 'STATION' ? 'station' : targetObj.deptType == 'BRIGADE' ? 'brigade' : 'department'
168
+            targetObj = this.levelOptions.find(item => item.id == value);
169
+            this.selectedLevelId = targetObj.value
170
+            this.selectedLevelType = targetObj.deptType == 'STATION' ? 'station' : 'department'
191 171
             this.loadData()
192 172
         },
193 173
         loadData() {
@@ -213,11 +193,11 @@ export default {
213 193
         },
214 194
         //获取抽问抽答完成率
215 195
         getLevelRateData() {
216
-            let params = {};
196
+            let params = {}
217 197
             let api = this.selectedLevelType == 'station' ? getStationLevelRate : getDepartmentLevelRate
218 198
             if (this.selectedLevelType == 'station') {
219 199
                 params.siteId = this.selectedLevelId
220
-            } else if (this.selectedLevelType == 'department' || this.selectedLevelType == 'brigade') {
200
+            } else if (this.selectedLevelType == 'department') {
221 201
                 params.deptId = this.selectedLevelId
222 202
             }
223 203
             api(params).then(res => {
@@ -251,6 +231,7 @@ export default {
251 231
 
252 232
                 })
253 233
             }
234
+
254 235
             if (this.isJingLi) {
255 236
 
256 237
                 const deptId = this.currentUser.deptId;
@@ -302,16 +283,11 @@ export default {
302 283
             let otherparams = {
303 284
                 deptId: this.selectedLevelId || ''
304 285
             }
305
-            console.log("params===", params, this.selectedLevelType)
306 286
             if (this.selectedLevelType == 'station') {
307 287
                 params.checkedSiteId = this.selectedLevelId
308
-            } 
309
-            if (this.selectedLevelType == 'department') {
288
+            } else if (this.selectedLevelType == 'department') {
310 289
                 params.checkedDepartmentId = this.selectedLevelId
311 290
             }
312
-            if (this.selectedLevelType == 'brigade') {
313
-                params.checkedBrigadeId = this.selectedLevelId
314
-            }
315 291
             getPortrait(params).then(res => {
316 292
                 this.portraitData = res.data || {};
317 293
             })