소스 검색

feat: 员工画像接口增强(基本信息、获奖、配分明细、质控)

- EmployeePortraitVO 新增 birthday/major/roleNames/postNames/qualityControlCount/scoreDetails 字段
- AwardRecord 改为 level2/3/4Name + score 结构
- 新增 ScoreDetail 内部类(维度名/二三级指标/分值)
- EmployeePortraitServiceImpl:从身份证提取出生日期,关联查询角色/岗位名称
- fillAwards 改为从 score_event(dimension_id=5) 查询获奖记录
- fillScoreDetails 汇总员工加减分明细列表
- LedgerSeizureStatsMapper 新增 countByInspectorAndDateRange 方法及 XML

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
simonlll 1 개월 전
부모
커밋
37234630a3

+ 58 - 11
airport-ledger/src/main/java/com/sundot/airport/ledger/domain/vo/EmployeePortraitVO.java

@@ -27,6 +27,10 @@ public class EmployeePortraitVO {
27 27
     private String characterCharacteristics;
28 28
     private String workingStyle;
29 29
     private String phonenumber;
30
+    private String birthday;       // 出生日期,从身份证计算
31
+    private String major;          // 专业(新增字段)
32
+    private String roleNames;      // 职务(来自 sys_role)
33
+    private String postNames;      // 岗位(来自 sys_post)
30 34
 
31 35
     @JsonFormat(pattern = "yyyy-MM-dd")
32 36
     private Date startWorkingDate;
@@ -60,6 +64,14 @@ public class EmployeePortraitVO {
60 64
 
61 65
     private List<AwardRecord> awards;
62 66
 
67
+    // ── 质控情况 ──────────────────────────────────────────────────────────────
68
+
69
+    private Integer qualityControlCount;   // 查获违规品次数
70
+
71
+    // ── 配分明细(加分+扣分全量) ──────────────────────────────────────────────
72
+
73
+    private List<ScoreDetail> scoreDetails;
74
+
63 75
     // ── getter / setter ───────────────────────────────────────────────────────
64 76
 
65 77
     public Long getUserId() { return userId; }
@@ -104,6 +116,18 @@ public class EmployeePortraitVO {
104 116
     public String getPhonenumber() { return phonenumber; }
105 117
     public void setPhonenumber(String phonenumber) { this.phonenumber = phonenumber; }
106 118
 
119
+    public String getBirthday() { return birthday; }
120
+    public void setBirthday(String birthday) { this.birthday = birthday; }
121
+
122
+    public String getMajor() { return major; }
123
+    public void setMajor(String major) { this.major = major; }
124
+
125
+    public String getRoleNames() { return roleNames; }
126
+    public void setRoleNames(String roleNames) { this.roleNames = roleNames; }
127
+
128
+    public String getPostNames() { return postNames; }
129
+    public void setPostNames(String postNames) { this.postNames = postNames; }
130
+
107 131
     public Date getStartWorkingDate() { return startWorkingDate; }
108 132
     public void setStartWorkingDate(Date startWorkingDate) { this.startWorkingDate = startWorkingDate; }
109 133
 
@@ -169,23 +193,46 @@ public class EmployeePortraitVO {
169 193
     }
170 194
 
171 195
     public static class AwardRecord {
172
-        private String type;
173
-        private String content;
174
-        private BigDecimal score;
196
+        private String level2Name;   // 二级指标
197
+        private String level3Name;   // 三级指标
198
+        private String level4Name;   // 四级指标
199
+        private BigDecimal score;    // 获奖情况(分值)
175 200
 
176
-        @JsonFormat(pattern = "yyyy-MM-dd")
177
-        private Date date;
201
+        public String getLevel2Name() { return level2Name; }
202
+        public void setLevel2Name(String level2Name) { this.level2Name = level2Name; }
178 203
 
179
-        public String getType() { return type; }
180
-        public void setType(String type) { this.type = type; }
204
+        public String getLevel3Name() { return level3Name; }
205
+        public void setLevel3Name(String level3Name) { this.level3Name = level3Name; }
181 206
 
182
-        public String getContent() { return content; }
183
-        public void setContent(String content) { this.content = content; }
207
+        public String getLevel4Name() { return level4Name; }
208
+        public void setLevel4Name(String level4Name) { this.level4Name = level4Name; }
184 209
 
185 210
         public BigDecimal getScore() { return score; }
186 211
         public void setScore(BigDecimal score) { this.score = score; }
212
+    }
213
+
214
+    public Integer getQualityControlCount() { return qualityControlCount; }
215
+    public void setQualityControlCount(Integer qualityControlCount) { this.qualityControlCount = qualityControlCount; }
216
+
217
+    public List<ScoreDetail> getScoreDetails() { return scoreDetails; }
218
+    public void setScoreDetails(List<ScoreDetail> scoreDetails) { this.scoreDetails = scoreDetails; }
219
+
220
+    public static class ScoreDetail {
221
+        private String dimensionName;
222
+        private String level2Name;
223
+        private String level3Name;
224
+        private BigDecimal totalScore;
225
+
226
+        public String getDimensionName() { return dimensionName; }
227
+        public void setDimensionName(String dimensionName) { this.dimensionName = dimensionName; }
228
+
229
+        public String getLevel2Name() { return level2Name; }
230
+        public void setLevel2Name(String level2Name) { this.level2Name = level2Name; }
231
+
232
+        public String getLevel3Name() { return level3Name; }
233
+        public void setLevel3Name(String level3Name) { this.level3Name = level3Name; }
187 234
 
188
-        public Date getDate() { return date; }
189
-        public void setDate(Date date) { this.date = date; }
235
+        public BigDecimal getTotalScore() { return totalScore; }
236
+        public void setTotalScore(BigDecimal totalScore) { this.totalScore = totalScore; }
190 237
     }
191 238
 }

+ 5 - 0
airport-ledger/src/main/java/com/sundot/airport/ledger/mapper/LedgerSeizureStatsMapper.java

@@ -3,10 +3,15 @@ package com.sundot.airport.ledger.mapper;
3 3
 import java.util.List;
4 4
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 5
 import com.sundot.airport.ledger.domain.LedgerSeizureStats;
6
+import org.apache.ibatis.annotations.Param;
6 7
 
7 8
 /**
8 9
  * 查获违规品统计Mapper接口
9 10
  */
10 11
 public interface LedgerSeizureStatsMapper extends BaseMapper<LedgerSeizureStats> {
11 12
     List<LedgerSeizureStats> selectList(LedgerSeizureStats query);
13
+
14
+    int countByInspectorAndDateRange(@Param("inspectorName") String inspectorName,
15
+                                     @Param("beginTime")     String beginTime,
16
+                                     @Param("endTime")       String endTime);
12 17
 }

+ 92 - 37
airport-ledger/src/main/java/com/sundot/airport/ledger/service/impl/EmployeePortraitServiceImpl.java

@@ -2,19 +2,20 @@ package com.sundot.airport.ledger.service.impl;
2 2
 
3 3
 import com.sundot.airport.common.core.domain.entity.SysDept;
4 4
 import com.sundot.airport.common.core.domain.entity.SysUser;
5
-import com.sundot.airport.ledger.domain.LedgerBannerLetter;
6 5
 import com.sundot.airport.ledger.domain.LedgerExamScore;
7
-import com.sundot.airport.ledger.domain.LedgerTerminalBonus;
8 6
 import com.sundot.airport.ledger.domain.ScoreDimension;
9 7
 import com.sundot.airport.ledger.domain.ScoreEvent;
10 8
 import com.sundot.airport.ledger.domain.vo.EmployeePortraitVO;
11
-import com.sundot.airport.ledger.mapper.LedgerBannerLetterMapper;
12 9
 import com.sundot.airport.ledger.mapper.LedgerExamScoreMapper;
13
-import com.sundot.airport.ledger.mapper.LedgerTerminalBonusMapper;
10
+import com.sundot.airport.ledger.mapper.LedgerSeizureStatsMapper;
14 11
 import com.sundot.airport.ledger.mapper.ScoreDimensionMapper;
15 12
 import com.sundot.airport.ledger.mapper.ScoreEventMapper;
16 13
 import com.sundot.airport.ledger.service.IEmployeePortraitService;
14
+import com.sundot.airport.system.domain.SysPost;
15
+import com.sundot.airport.common.core.domain.entity.SysRole;
17 16
 import com.sundot.airport.system.mapper.SysDeptMapper;
17
+import com.sundot.airport.system.mapper.SysPostMapper;
18
+import com.sundot.airport.system.mapper.SysRoleMapper;
18 19
 import com.sundot.airport.system.mapper.SysUserMapper;
19 20
 import org.springframework.beans.factory.annotation.Autowired;
20 21
 import org.springframework.stereotype.Service;
@@ -34,6 +35,12 @@ public class EmployeePortraitServiceImpl implements IEmployeePortraitService {
34 35
     private SysDeptMapper sysDeptMapper;
35 36
 
36 37
     @Autowired
38
+    private SysRoleMapper sysRoleMapper;
39
+
40
+    @Autowired
41
+    private SysPostMapper sysPostMapper;
42
+
43
+    @Autowired
37 44
     private ScoreEventMapper scoreEventMapper;
38 45
 
39 46
     @Autowired
@@ -43,10 +50,7 @@ public class EmployeePortraitServiceImpl implements IEmployeePortraitService {
43 50
     private LedgerExamScoreMapper ledgerExamScoreMapper;
44 51
 
45 52
     @Autowired
46
-    private LedgerBannerLetterMapper ledgerBannerLetterMapper;
47
-
48
-    @Autowired
49
-    private LedgerTerminalBonusMapper ledgerTerminalBonusMapper;
53
+    private LedgerSeizureStatsMapper ledgerSeizureStatsMapper;
50 54
 
51 55
     // ── 搜索员工 ─────────────────────────────────────────────────────────────
52 56
 
@@ -85,9 +89,16 @@ public class EmployeePortraitServiceImpl implements IEmployeePortraitService {
85 89
         // 3. 最新考试成绩
86 90
         fillExamScore(vo, personName);
87 91
 
88
-        // 4. 获奖记录(锦旗/感谢信 + 航站楼加分)
92
+        // 4. 获奖记录
89 93
         fillAwards(vo, personName);
90 94
 
95
+        // 5. 配分明细(全量加减分)
96
+        fillScoreDetails(vo, personName, beginTime, endTime);
97
+
98
+        // 6. 质控情况
99
+        int qcCount = ledgerSeizureStatsMapper.countByInspectorAndDateRange(personName, beginTime, endTime);
100
+        vo.setQualityControlCount(qcCount);
101
+
91 102
         return vo;
92 103
     }
93 104
 
@@ -127,6 +138,33 @@ public class EmployeePortraitServiceImpl implements IEmployeePortraitService {
127 138
             vo.setSecurityCheckYears((int) ((nowMs - user.getSecurityCheckStartDate().getTime()) / (365L * 24 * 3600 * 1000)));
128 139
         }
129 140
 
141
+        // 出生日期(从18位身份证第7~14位提取)
142
+        String card = user.getCardNumber();
143
+        if (card != null && card.length() >= 14) {
144
+            String bd = card.substring(6, 14);
145
+            vo.setBirthday(bd.substring(0, 4) + "-" + bd.substring(4, 6) + "-" + bd.substring(6, 8));
146
+        }
147
+
148
+        // 职务(sys_role)
149
+        List<SysRole> roles = sysRoleMapper.selectRolesByUserName(user.getUserName());
150
+        if (roles != null && !roles.isEmpty()) {
151
+            String rn = roles.stream()
152
+                    .map(SysRole::getRoleName)
153
+                    .filter(s -> s != null && !s.isEmpty())
154
+                    .collect(Collectors.joining("、"));
155
+            vo.setRoleNames(rn);
156
+        }
157
+
158
+        // 岗位(sys_post)
159
+        List<SysPost> posts = sysPostMapper.selectPostsByUserName(user.getUserName());
160
+        if (posts != null && !posts.isEmpty()) {
161
+            String pn = posts.stream()
162
+                    .map(SysPost::getPostName)
163
+                    .filter(s -> s != null && !s.isEmpty())
164
+                    .collect(Collectors.joining("、"));
165
+            vo.setPostNames(pn);
166
+        }
167
+
130 168
         // 部门路径
131 169
         if (user.getDept() != null) {
132 170
             String deptName = user.getDept().getDeptName();
@@ -225,40 +263,57 @@ public class EmployeePortraitServiceImpl implements IEmployeePortraitService {
225 263
 
226 264
     // ── 获奖记录 ──────────────────────────────────────────────────────────────
227 265
 
228
-    private void fillAwards(EmployeePortraitVO vo, String personName) {
229
-        List<EmployeePortraitVO.AwardRecord> awards = new ArrayList<>();
266
+    private void fillScoreDetails(EmployeePortraitVO vo, String personName, String beginTime, String endTime) {
267
+        ScoreEvent eq = new ScoreEvent();
268
+        eq.setPersonName(personName);
269
+        if (beginTime != null && !beginTime.isEmpty()) eq.getParams().put("beginTime", beginTime);
270
+        if (endTime   != null && !endTime.isEmpty())   eq.getParams().put("endTime",   endTime);
271
+        List<ScoreEvent> events = scoreEventMapper.selectList(eq);
230 272
 
231
-        // 锦旗及感谢信
232
-        LedgerBannerLetter bq = new LedgerBannerLetter();
233
-        bq.setPersonName(personName);
234
-        for (LedgerBannerLetter b : ledgerBannerLetterMapper.selectList(bq)) {
235
-            EmployeePortraitVO.AwardRecord ar = new EmployeePortraitVO.AwardRecord();
236
-            ar.setType("1".equals(b.getType()) ? "锦旗" : "感谢信");
237
-            ar.setContent(b.getContentDesc());
238
-            ar.setScore(b.getAddScore());
239
-            ar.setDate(b.getRecordDate());
240
-            awards.add(ar);
273
+        List<EmployeePortraitVO.ScoreDetail> details = new ArrayList<>();
274
+        for (ScoreEvent e : events) {
275
+            String raw = e.getPersonName();
276
+            if (raw == null) continue;
277
+            boolean matched = false;
278
+            for (String n : raw.split("[,,]")) {
279
+                if (personName.equals(n.trim())) { matched = true; break; }
280
+            }
281
+            if (!matched) continue;
282
+
283
+            EmployeePortraitVO.ScoreDetail d = new EmployeePortraitVO.ScoreDetail();
284
+            d.setDimensionName(e.getDimensionName());
285
+            d.setLevel2Name(e.getLevel2Name());
286
+            d.setLevel3Name(e.getLevel3Name());
287
+            d.setTotalScore(e.getTotalScore());
288
+            details.add(d);
241 289
         }
290
+        vo.setScoreDetails(details);
291
+    }
292
+
293
+    private void fillAwards(EmployeePortraitVO vo, String personName) {
294
+        // 群团协作能力 dimension_id = 5
295
+        ScoreEvent eq = new ScoreEvent();
296
+        eq.setPersonName(personName);
297
+        eq.setDimensionId(5L);
298
+        List<ScoreEvent> events = scoreEventMapper.selectList(eq);
299
+
300
+        List<EmployeePortraitVO.AwardRecord> awards = new ArrayList<>();
301
+        for (ScoreEvent e : events) {
302
+            String raw = e.getPersonName();
303
+            if (raw == null) continue;
304
+            boolean matched = false;
305
+            for (String n : raw.split("[,,]")) {
306
+                if (personName.equals(n.trim())) { matched = true; break; }
307
+            }
308
+            if (!matched) continue;
242 309
 
243
-        // 航站楼加分
244
-        LedgerTerminalBonus tq = new LedgerTerminalBonus();
245
-        tq.setPersonName(personName);
246
-        for (LedgerTerminalBonus t : ledgerTerminalBonusMapper.selectList(tq)) {
247 310
             EmployeePortraitVO.AwardRecord ar = new EmployeePortraitVO.AwardRecord();
248
-            ar.setType("航站楼加分");
249
-            ar.setContent(t.getBonusType());
250
-            ar.setScore(t.getAddScore());
251
-            ar.setDate(t.getApproveDate());
311
+            ar.setLevel3Name(e.getLevel3Name());
312
+            ar.setLevel2Name(e.getLevel2Name());
313
+            ar.setLevel4Name(e.getLevel4Name());
314
+            ar.setScore(e.getTotalScore());
252 315
             awards.add(ar);
253 316
         }
254
-
255
-        // 按日期降序
256
-        awards.sort((a, b) -> {
257
-            if (a.getDate() == null) return 1;
258
-            if (b.getDate() == null) return -1;
259
-            return b.getDate().compareTo(a.getDate());
260
-        });
261
-
262 317
         vo.setAwards(awards);
263 318
     }
264 319
 

+ 14 - 0
airport-ledger/src/main/resources/mapper/ledger/LedgerSeizureStatsMapper.xml

@@ -50,4 +50,18 @@
50 50
         ORDER BY id DESC
51 51
     </select>
52 52
 
53
+
54
+    <select id="countByInspectorAndDateRange" resultType="int">
55
+        SELECT count(*)
56
+        FROM ledger_seizure_stats
57
+        WHERE del_flag = '0'
58
+          AND inspector_name = #{inspectorName}
59
+          <if test="beginTime != null and beginTime != ''">
60
+              AND record_date &gt;= STR_TO_DATE(#{beginTime}, '%Y-%m-%d')
61
+          </if>
62
+          <if test="endTime != null and endTime != ''">
63
+              AND record_date &lt;= STR_TO_DATE(#{endTime}, '%Y-%m-%d')
64
+          </if>
65
+    </select>
66
+
53 67
 </mapper>