shinnosuke
4 天以前 38e39c50dcca12534c4efe2b49355a97c396b507
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
package com.talentcard.server.business.portal;
 
import java.time.LocalDate;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
import com.talentcard.server.business.BusinessIdGenerator;
import com.talentcard.server.business.DatabaseRows;
import com.talentcard.server.common.BusinessException;
import com.talentcard.server.common.ErrorCode;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
@Service
public class CardUpgradePortalService {
 
    private static final List<String> CARD_LEVELS = List.of("菁英人才卡", "杰出人才卡", "卓越人才卡");
 
    private final JdbcTemplate jdbcTemplate;
 
    public CardUpgradePortalService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
 
    @Transactional(readOnly = true)
    public Map<String, Object> current(Long talentId) {
        Map<String, Object> card = currentCard(talentId);
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("currentCardLevel", card.get("cardLevel"));
        result.put("targetCardLevels", targetLevels(String.valueOf(card.get("cardLevel"))));
        latestApplication(talentId).ifPresent(application -> result.put("application", application));
        return result;
    }
 
    @Transactional
    public Map<String, Object> submit(CardUpgradeRequest request, String idempotencyKey) {
        if (idempotencyKey == null || idempotencyKey.isBlank() || idempotencyKey.length() > 128) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "提交凭证不能为空");
        }
        List<Map<String, Object>> duplicates = query("select id from upgrade_application where idempotency_key = ?", idempotencyKey);
        if (!duplicates.isEmpty()) {
            return application(((Number) duplicates.get(0).get("id")).longValue());
        }
 
        Map<String, Object> card = currentCard(request.talentId());
        List<String> targetLevels = targetLevels(String.valueOf(card.get("cardLevel")));
        if (!targetLevels.contains(request.targetCardLevel())) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "目标人才卡等级不正确");
        }
        validateHonors(request.honors());
 
        String applicationNo = BusinessIdGenerator.next("UP");
        jdbcTemplate.update("""
                insert into upgrade_application(application_no, talent_id, talent_name, talent_mobile, talent_card_no,
                                                current_level, target_level, apply_reason, apply_time, status, idempotency_key)
                select ?, t.id, t.name, t.mobile, ?, ?, ?, ?, now(), '待审核', ?
                from talent_user t where t.id = ? and t.deleted = 0
                """,
                applicationNo,
                card.get("cardNo"),
                card.get("cardLevel"),
                request.targetCardLevel(),
                "通过人才端提交升级申请",
                idempotencyKey,
                request.talentId());
        Long applicationId = jdbcTemplate.queryForObject("select id from upgrade_application where idempotency_key = ?", Long.class, idempotencyKey);
        if (applicationId == null) {
            throw new BusinessException(ErrorCode.INTERNAL_ERROR, "升级申请创建失败");
        }
        for (int index = 0; index < request.honors().size(); index++) {
            CardUpgradeRequest.Honor honor = request.honors().get(index);
            jdbcTemplate.update("""
                    insert into upgrade_application_honor(application_id, honor_name, obtained_date, proof_file_id, sort_no)
                    values (?, ?, ?, ?, ?)
                    """, applicationId, honor.name().trim(), LocalDate.parse(honor.obtainedDate()), honor.proofFileIds().get(0), index + 1);
        }
        return application(applicationId);
    }
 
    private void validateHonors(List<CardUpgradeRequest.Honor> honors) {
        for (CardUpgradeRequest.Honor honor : honors) {
            try {
                LocalDate obtainedDate = LocalDate.parse(honor.obtainedDate());
                if (obtainedDate.isAfter(LocalDate.now())) throw new BusinessException(ErrorCode.BAD_REQUEST, "获得时间不能晚于今天");
            } catch (java.time.format.DateTimeParseException exception) {
                throw new BusinessException(ErrorCode.BAD_REQUEST, "获得时间格式不正确");
            }
            for (String proofFileId : honor.proofFileIds()) {
                if (proofFileId == null || !proofFileId.startsWith("/uploads/")) {
                    throw new BusinessException(ErrorCode.BAD_REQUEST, "印证资料文件不正确");
                }
            }
        }
    }
 
    private Map<String, Object> currentCard(Long talentId) {
        if (talentId == null) throw new BusinessException(ErrorCode.BAD_REQUEST, "人才信息不能为空");
        List<Map<String, Object>> cards = query("""
                select id as card_id, card_no, card_level
                from talent_card
                where deleted = 0 and talent_id = ? and card_type = 'PERSONAL' and status = 1
                order by id desc limit 1
                """, talentId);
        if (cards.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "未找到有效人才卡");
        return cards.get(0);
    }
 
    private List<String> targetLevels(String currentLevel) {
        int currentIndex = CARD_LEVELS.indexOf(currentLevel);
        if (currentIndex < 0 || currentIndex == CARD_LEVELS.size() - 1) return List.of();
        return CARD_LEVELS.subList(currentIndex + 1, CARD_LEVELS.size());
    }
 
    private java.util.Optional<Map<String, Object>> latestApplication(Long talentId) {
        List<Map<String, Object>> applications = query("""
                select id from upgrade_application
                where talent_id = ? and deleted = 0
                order by apply_time desc, id desc limit 1
                """, talentId);
        return applications.isEmpty() ? java.util.Optional.empty() : java.util.Optional.of(application(((Number) applications.get(0).get("id")).longValue()));
    }
 
    private Map<String, Object> application(Long applicationId) {
        List<Map<String, Object>> applications = query("select * from upgrade_application where id = ? and deleted = 0", applicationId);
        if (applications.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "升级申请不存在");
        Map<String, Object> row = applications.get(0);
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("applicationId", String.valueOf(row.get("id")));
        result.put("targetCardLevel", row.get("targetLevel"));
        result.put("status", applicationStatus(String.valueOf(row.get("status"))));
        result.put("rejectReason", row.get("auditRemark"));
        result.put("honors", query("""
                select honor_name as name, obtained_date, proof_file_id
                from upgrade_application_honor where application_id = ? order by sort_no, id
                """, applicationId).stream().map(honor -> Map.of(
                        "name", honor.get("name"),
                        "obtainedDate", String.valueOf(honor.get("obtainedDate")),
                        "proofFileIds", List.of(honor.get("proofFileId"))
                )).toList());
        return result;
    }
 
    private String applicationStatus(String status) {
        return switch (status) {
            case "已通过" -> "approved";
            case "已驳回" -> "rejected";
            case "草稿" -> "draft";
            default -> "reviewing";
        };
    }
 
    private List<Map<String, Object>> query(String sql, Object... args) {
        return DatabaseRows.normalize(jdbcTemplate.queryForList(sql, args));
    }
}