package com.talentcard.server.service;
|
|
import java.net.URI;
|
import java.util.Arrays;
|
import java.util.LinkedHashMap;
|
import java.util.Locale;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.stream.Collectors;
|
|
import com.talentcard.server.common.BusinessException;
|
import com.talentcard.server.common.ErrorCode;
|
import com.talentcard.server.mapper.TransportCarWashServiceMapper;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
@Service
|
public class CarWashJumpConfigPortalService {
|
private final TransportCarWashServiceMapper serviceMapper;
|
private final Set<String> allowedWebHosts;
|
|
public CarWashJumpConfigPortalService(
|
TransportCarWashServiceMapper serviceMapper,
|
@Value("${app.external-web.allowed-hosts:}") String allowedWebHosts
|
) {
|
this.serviceMapper = serviceMapper;
|
this.allowedWebHosts = Arrays.stream(allowedWebHosts.split(","))
|
.map(String::trim)
|
.filter(value -> !value.isEmpty())
|
.map(value -> value.toLowerCase(Locale.ROOT))
|
.collect(Collectors.toUnmodifiableSet());
|
}
|
|
@Transactional(readOnly = true)
|
public Map<String, Object> jumpConfig(Long merchantId) {
|
Long id = requireMerchantId(merchantId);
|
Map<String, Object> row = serviceMapper.selectPortalJumpConfig(id);
|
if (row == null || row.isEmpty()) {
|
throw new BusinessException(ErrorCode.NOT_FOUND, "洗车商家不存在");
|
}
|
|
boolean merchantEnabled = intValue(row, "merchantStatus", "merchant_status") == 1;
|
boolean serviceConfigured = value(row, "configId", "config_id") != null;
|
boolean serviceEnabled = intValue(row, "serviceStatus", "service_status") == 1;
|
boolean available = merchantEnabled && serviceConfigured && serviceEnabled;
|
|
Map<String, Object> result = new LinkedHashMap<>();
|
result.put("merchantId", value(row, "merchantId", "merchant_id"));
|
result.put("merchantName", text(row, "merchantName", "merchant_name"));
|
result.put("available", available);
|
result.put("unavailableReason", unavailableReason(row, available, merchantEnabled, serviceConfigured, serviceEnabled));
|
applyExternalLink(result, row, available);
|
result.put("updatedAt", value(row, "updatedAt", "updated_at"));
|
return result;
|
}
|
|
private void applyExternalLink(Map<String, Object> result, Map<String, Object> row, boolean available) {
|
if (available) {
|
String type = text(row, "externalLinkType", "external_link_type");
|
if ("miniProgram".equals(type)) {
|
String appId = text(row, "externalMiniProgramAppId", "external_mini_program_app_id");
|
if (appId.matches("^wx[a-zA-Z0-9]{16}$")) {
|
result.put("externalLinkType", "miniProgram");
|
result.put("externalMiniProgramAppId", appId);
|
result.put("externalMiniProgramPath", text(row, "externalMiniProgramPath", "external_mini_program_path"));
|
result.put("externalWebUrl", "");
|
return;
|
}
|
}
|
if ("web".equals(type)) {
|
String webUrl = text(row, "externalWebUrl", "external_web_url");
|
if (isAllowedWebUrl(webUrl)) {
|
result.put("externalLinkType", "web");
|
result.put("externalMiniProgramAppId", "");
|
result.put("externalMiniProgramPath", "");
|
result.put("externalWebUrl", webUrl);
|
return;
|
}
|
}
|
}
|
result.put("externalLinkType", "");
|
result.put("externalMiniProgramAppId", "");
|
result.put("externalMiniProgramPath", "");
|
result.put("externalWebUrl", "");
|
}
|
|
private String unavailableReason(Map<String, Object> row,
|
boolean available,
|
boolean merchantEnabled,
|
boolean serviceConfigured,
|
boolean serviceEnabled) {
|
if (available) {
|
return "";
|
}
|
if (!merchantEnabled) {
|
return "洗车商家当前不可用";
|
}
|
if (!serviceConfigured) {
|
return "洗车服务配置不存在";
|
}
|
if (!serviceEnabled) {
|
String configuredReason = text(row, "unavailableReason", "unavailable_reason");
|
return configuredReason.isBlank() ? "洗车服务当前不可用" : configuredReason;
|
}
|
return "洗车跳转配置不可用";
|
}
|
|
private boolean isAllowedWebUrl(String value) {
|
if (value.isBlank() || allowedWebHosts.isEmpty()) {
|
return false;
|
}
|
try {
|
URI uri = URI.create(value);
|
String host = uri.getHost();
|
return "https".equalsIgnoreCase(uri.getScheme())
|
&& host != null
|
&& uri.getUserInfo() == null
|
&& allowedWebHosts.contains(host.toLowerCase(Locale.ROOT));
|
} catch (IllegalArgumentException exception) {
|
return false;
|
}
|
}
|
|
private Long requireMerchantId(Long merchantId) {
|
if (merchantId == null || merchantId <= 0) {
|
throw new BusinessException(ErrorCode.BAD_REQUEST, "洗车商家ID不能为空");
|
}
|
return merchantId;
|
}
|
|
private Object value(Map<String, Object> row, String... keys) {
|
for (String key : keys) {
|
if (row.containsKey(key)) {
|
return row.get(key);
|
}
|
}
|
return null;
|
}
|
|
private String text(Map<String, Object> row, String... keys) {
|
Object value = value(row, keys);
|
return value == null ? "" : String.valueOf(value).trim();
|
}
|
|
private int intValue(Map<String, Object> row, String... keys) {
|
Object value = value(row, keys);
|
return value instanceof Number number ? number.intValue() : 0;
|
}
|
}
|