shinnosuke
2026-08-19 ac44d2c693c433ed230652ed3f1f6516042309c5
talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
@@ -30,8 +30,9 @@
public class AdminBusinessService {
   private static final Set<String> MERCHANT_APP_LOGIN_TYPES = Set.of(
         "餐饮服务", "景区服务", "购房优惠", "购车服务", "家电服务", "数码服务",
         "文化服务", "电信服务", "口腔治疗保健", "加油服务"
         "餐饮服务", "景区服务", "免费体检", "配偶推荐就业", "金融服务", "行政审批", "子女托管",
         "酒店服务", "公寓租赁", "加油服务", "停车服务", "自助洗车", "购房优惠", "购车服务",
         "家电服务", "数码服务", "文化服务", "电信服务", "口腔治疗保健"
   );
   private final JdbcTemplate jdbcTemplate;
@@ -388,6 +389,7 @@
            request.recommend() == null ? defaultRecommend(request.merchantType()) : request.recommend(),
            request.sortNo() == null ? 0 : request.sortNo());
      Long id = jdbcTemplate.queryForObject("select last_insert_id()", Long.class);
      ensureParkingBenefit(id, request.merchantType());
      Long storeId = createDefaultStore(id, request.merchantName(), request.address());
      syncMerchantBusinessHours(id, storeId, request.businessHours());
      if (hasMerchantAppAccess(request)) {
@@ -512,6 +514,7 @@
            request.status() == null ? 1 : request.status(),
            id);
      ensureUpdated(updated);
      ensureParkingBenefit(id, request.merchantType());
      Long storeId = findOrCreateDefaultStore(id, request.merchantName(), request.address());
      syncMerchantBusinessHours(id, storeId, request.businessHours());
      if (request.loginPassword() != null && !request.loginPassword().isBlank()) {
@@ -523,11 +526,42 @@
               set password_hash = ?
               where merchant_id = ? and role_code = 'owner' and deleted = 0
               """, MerchantPasswordHasher.encode(request.loginPassword()), id);
         if (passwordUpdated == 0) throw new BusinessException(ErrorCode.CONFLICT, "该商家未配置商户端登录账号");
         if (passwordUpdated == 0) {
            createMerchantOperator(id, request);
         }
      }
      if ((request.loginPassword() == null || request.loginPassword().isBlank()) && supportsMerchantAppLogin(request.merchantType())
            && (request.canLoginMerchantApp() == null || request.canLoginMerchantApp() == 1)
            && (request.loginAccount() != null && !request.loginAccount().isBlank())) {
         createMerchantOperator(id, request);
      }
      return merchant(id);
   }
   private void createMerchantOperator(Long merchantId, MerchantUpdateRequest request) {
      if (request.loginAccount() == null || !request.loginAccount().trim().matches("^[A-Za-z0-9]{1,32}$")) {
         throw new BusinessException(ErrorCode.BAD_REQUEST, "商户登录账号只能包含英文字母和数字");
      }
      if (request.loginPassword() == null || request.loginPassword().length() < 6 || request.loginPassword().length() > 64) {
         throw new BusinessException(ErrorCode.BAD_REQUEST, "商户登录密码长度须为6至64位");
      }
      Integer occupied = jdbcTemplate.queryForObject("select count(*) from merchant_operator where account = ? and deleted = 0", Integer.class, request.loginAccount().trim());
      if (occupied != null && occupied > 0) throw new BusinessException(ErrorCode.CONFLICT, "登录账号已存在");
      jdbcTemplate.update("insert into merchant_operator(merchant_id, account, password_hash, display_name, role_code, status) values (?, ?, ?, ?, 'owner', 1)",
            merchantId, request.loginAccount().trim(), MerchantPasswordHasher.encode(request.loginPassword()), request.merchantName().trim());
   }
   private void ensureParkingBenefit(Long merchantId, String merchantType) {
      if (!"停车服务".equals(merchantType) && !"parking".equalsIgnoreCase(merchantType)) return;
      jdbcTemplate.update("""
            insert into transport_parking_benefit(merchant_id, talent_levels, benefit_text, action_mode, plate_form_mode, usage_instructions, rule_text, status, deleted)
            select ?, '', '停车权益', 'plate', 'withParking',
                   '登记车牌后可享受当前停车场的人才专属停车权益。',
                   '具体免费时长、适用时段和停车场范围以现场说明为准。', 1, 0
            where not exists (select 1 from transport_parking_benefit where merchant_id = ? and deleted = 0)
            """, merchantId, merchantId);
   }
   @Transactional
   public Map<String, Object> updateMerchantStatus(Long id, Byte status) {
      int updated = jdbcTemplate.update("update merchant set status = ? where deleted = 0 and id = ?", status, id);