shinnosuke
2026-09-21 7844f5af457ff3b7d3f8eeac8799e8d281e635a1
talent-card-server/src/main/java/com/talentcard/server/business/auth/TalentAuthService.java
@@ -41,12 +41,15 @@
    @Transactional
    public Map<String, Object> createDevelopmentSession(long talentId) {
        List<Map<String, Object>> talents = rows("""
                select id, openid
                select id, openid, status
                from talent_user
                where id = ? and deleted = 0 and status = 1
                where id = ? and deleted = 0
                limit 1 for update
                """, talentId);
        if (talents.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "开发测试人才账号不存在或不可用");
        if (talents.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "开发测试人才账号不存在");
        if (number(talents.get(0).get("status")) != 1) {
            throw new BusinessException(ErrorCode.FORBIDDEN, "持卡人被停用");
        }
        Object openId = talents.get(0).get("openid");
        if (openId == null || String.valueOf(openId).isBlank()) {
            throw new BusinessException(ErrorCode.CONFLICT, "开发测试人才账号未配置微信标识");
@@ -103,22 +106,61 @@
    private Map<String, Object> establishSession(String openId, String mobile) {
        List<Map<String, Object>> talents = rows("""
                select id, openid
                select id, openid, status
                from talent_user
                where mobile = ? and deleted = 0 and status = 1
                where mobile = ? and deleted = 0
                limit 1 for update
                """, mobile);
        if (talents.isEmpty()) throw new BusinessException(ErrorCode.FORBIDDEN, "当前手机号未录入人才服务名单,请联系管理员");
        if (talents.isEmpty()) return issueSession(registerVisitor(openId, mobile));
        Map<String, Object> talent = talents.get(0);
        long talentId = number(talent.get("id"));
        List<Map<String, Object>> binding = rows("select id from talent_user where openid = ? and deleted = 0 limit 1 for update", openId);
        if (!binding.isEmpty() && number(binding.get(0).get("id")) != talentId) {
            throw new BusinessException(ErrorCode.CONFLICT, "当前微信已绑定其他人才账号,请联系管理员");
        if (number(talent.get("status")) != 1) {
            throw new BusinessException(ErrorCode.FORBIDDEN, "持卡人被停用");
        }
        long talentId = number(talent.get("id"));
        List<Map<String, Object>> binding = rows("""
                select t.id
                from talent_user t
                where t.openid = ? and t.deleted = 0
                limit 1 for update
                """, openId);
        if (!binding.isEmpty() && number(binding.get(0).get("id")) != talentId) {
            long previousTalentId = number(binding.get(0).get("id"));
            jdbc.update("update talent_session set revoked_at = coalesce(revoked_at, now()) where talent_id = ? and revoked_at is null", previousTalentId);
        }
        // uk_openid 是唯一索引:已软删/停用的历史账号照样占着这个 openid,不先摘掉就会撞唯一键(接口报「服务器内部错误」)。
        releaseOpenId(openId, talentId);
        jdbc.update("update talent_user set openid = ? where id = ?", openId, talentId);
        return issueSession(talentId);
    }
    /** 把 openid 从除 keepTalentId 之外的所有行上摘掉(含软删、停用的历史账号)。 */
    private void releaseOpenId(String openId, long keepTalentId) {
        jdbc.update("update talent_user set openid = null where openid = ? and id <> ?", openId, keepTalentId);
    }
    private long registerVisitor(String openId, String mobile) {
        List<Map<String, Object>> bindings = rows("""
                select id
                from talent_user
                where openid = ? and deleted = 0 and status = 1
                limit 1 for update
                """, openId);
        if (!bindings.isEmpty()) {
            long talentId = number(bindings.get(0).get("id"));
            jdbc.update("update talent_user set mobile = ? where id = ?", mobile, talentId);
            return talentId;
        }
        // 没有可用的绑定时要把历史占用清掉,否则下面这条 insert 会撞 uk_openid。
        jdbc.update("update talent_user set openid = null where openid = ?", openId);
        jdbc.update("""
                insert into talent_user(openid, name, mobile, talent_level, source_area_type, status)
                values (?, '普通游客', ?, '普通游客', 'LOCAL', 1)
                """, openId, mobile);
        Long talentId = jdbc.queryForObject("select last_insert_id()", Long.class);
        if (talentId == null) throw new BusinessException(ErrorCode.INTERNAL_ERROR, "普通游客注册失败");
        return talentId;
    }
    private Map<String, Object> issueSession(long talentId) {
        jdbc.update("update talent_session set revoked_at = now() where talent_id = ? and revoked_at is null", talentId);