shinnosuke
2026-09-25 66c0d9abbcb9f7b4407784ba4c886ce94a8b55dc
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
package com.talentcard.server.business.portal;
 
import java.sql.Date;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
 
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 ChildInformationPortalService {
 
    private final JdbcTemplate jdbc;
 
    public ChildInformationPortalService(JdbcTemplate jdbc) {
        this.jdbc = jdbc;
    }
 
    @Transactional(readOnly = true)
    public List<Map<String, Object>> list(Long talentId) {
        ensureTalent(talentId);
        return query("""
                select id, child_name, gender, birth_date, audit_status, reject_reason, created_at, submitted_at
                from child_information where talent_id = ? and deleted = 0
                order by created_at desc, id desc
                """, talentId).stream().map(this::listView).toList();
    }
 
    @Transactional(readOnly = true)
    public Map<String, Object> detail(Long childId, Long talentId) {
        Map<String, Object> row = child(childId, talentId);
        if (!"审核不通过".equals(text(row.get("auditStatus")))) {
            throw new BusinessException(ErrorCode.CONFLICT, "当前子女资料不需要重新提交");
        }
        Map<String, Object> result = listView(row);
        result.put("canResubmit", true);
        return result;
    }
 
    @Transactional
    public Map<String, Object> create(ChildInformationRequest request, String idempotencyKey) {
        ensureTalent(request.talentId());
        validate(request, idempotencyKey);
        List<Map<String, Object>> duplicates = query("""
                select id from child_information where talent_id = ? and idempotency_key = ? and deleted = 0
                """, request.talentId(), idempotencyKey);
        if (!duplicates.isEmpty()) return listView(child(((Number) duplicates.get(0).get("id")).longValue(), request.talentId()));
        jdbc.update("""
                insert into child_information(talent_id, child_name, gender, birth_date, proof_file_ids, audit_status, idempotency_key, submitted_at)
                values (?, ?, ?, ?, ?, '待审核', ?, now())
                """, request.talentId(), clean(request.name()), clean(request.gender()), Date.valueOf(birthDate(request.birthDate())), proofIds(request.proofFileIds()), idempotencyKey);
        Long childId = jdbc.queryForObject("select id from child_information where talent_id = ? and idempotency_key = ?", Long.class, request.talentId(), idempotencyKey);
        if (childId == null) throw new BusinessException(ErrorCode.INTERNAL_ERROR, "子女资料提交失败");
        return listView(child(childId, request.talentId()));
    }
 
    @Transactional
    public Map<String, Object> resubmit(Long childId, ChildInformationRequest request, String idempotencyKey) {
        ensureTalent(request.talentId());
        validate(request, idempotencyKey);
        Map<String, Object> current = child(childId, request.talentId());
        if (idempotencyKey.equals(text(current.get("idempotencyKey")))) return listView(current);
        if (!"审核不通过".equals(text(current.get("auditStatus")))) {
            throw new BusinessException(ErrorCode.CONFLICT, "当前子女资料不允许重复提交");
        }
        jdbc.update("""
                update child_information
                set child_name = ?, gender = ?, birth_date = ?, proof_file_ids = ?, audit_status = '待审核',
                    reject_reason = null, idempotency_key = ?, submitted_at = now(), updated_at = now()
                where id = ? and talent_id = ? and deleted = 0
                """, clean(request.name()), clean(request.gender()), Date.valueOf(birthDate(request.birthDate())), proofIds(request.proofFileIds()), idempotencyKey, childId, request.talentId());
        return listView(child(childId, request.talentId()));
    }
 
    private Map<String, Object> child(Long childId, Long talentId) {
        if (childId == null || childId <= 0) throw new BusinessException(ErrorCode.BAD_REQUEST, "子女资料信息不能为空");
        List<Map<String, Object>> rows = query("""
                select id, child_name, gender, birth_date, audit_status, reject_reason, idempotency_key, created_at, submitted_at
                from child_information where id = ? and talent_id = ? and deleted = 0
                """, childId, talentId);
        if (rows.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "子女资料不存在或无权查看");
        return rows.get(0);
    }
 
    private Map<String, Object> listView(Map<String, Object> row) {
        Map<String, Object> result = new java.util.LinkedHashMap<>();
        result.put("id", row.get("id"));
        result.put("name", row.get("childName"));
        result.put("gender", row.get("gender"));
        result.put("birthDate", String.valueOf(row.get("birthDate")));
        result.put("status", text(row.get("auditStatus")));
        result.put("rejectReason", text(row.get("rejectReason")));
        result.put("createdAt", row.get("createdAt"));
        result.put("submittedAt", row.get("submittedAt"));
        return result;
    }
 
    private void ensureTalent(Long talentId) {
        if (talentId == null || talentId <= 0 || !Boolean.TRUE.equals(jdbc.queryForObject("select exists(select 1 from talent_user where id = ? and deleted = 0)", Boolean.class, talentId))) {
            throw new BusinessException(ErrorCode.NOT_FOUND, "人才用户不存在");
        }
    }
 
    private void validate(ChildInformationRequest request, String idempotencyKey) {
        if (idempotencyKey == null || idempotencyKey.isBlank() || idempotencyKey.length() > 128) throw new BusinessException(ErrorCode.BAD_REQUEST, "提交凭证不能为空");
        if (!List.of("男", "女").contains(clean(request.gender()))) throw new BusinessException(ErrorCode.BAD_REQUEST, "请选择有效的性别");
        if (request.proofFileIds().size() > 3 || request.proofFileIds().stream().anyMatch(id -> id == null || id.isBlank() || id.length() > 255)) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "证明材料格式不正确");
        }
        birthDate(request.birthDate());
    }
 
    private LocalDate birthDate(String value) {
        try {
            LocalDate date = LocalDate.parse(clean(value));
            if (date.isAfter(LocalDate.now())) throw new BusinessException(ErrorCode.BAD_REQUEST, "出生日期不能晚于今天");
            return date;
        } catch (DateTimeParseException error) {
            throw new BusinessException(ErrorCode.BAD_REQUEST, "出生日期格式不正确");
        }
    }
 
    private List<Map<String, Object>> query(String sql, Object... args) {
        return DatabaseRows.normalize(jdbc.queryForList(sql, args));
    }
 
    private String proofIds(List<String> values) {
        return values.stream().map(String::trim).collect(Collectors.joining(","));
    }
 
    private String clean(String value) {
        return value == null ? "" : value.trim();
    }
 
    private String text(Object value) {
        return value == null ? "" : String.valueOf(value);
    }
}