package com.talentcard.server.business.portal;
|
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
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;
|
import tools.jackson.core.type.TypeReference;
|
import tools.jackson.databind.ObjectMapper;
|
|
@Service
|
public class AdminApprovalPortalService {
|
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
private static final TypeReference<List<Map<String, Object>>> APPROVAL_ITEMS = new TypeReference<>() {};
|
|
private final JdbcTemplate jdbc;
|
|
public AdminApprovalPortalService(JdbcTemplate jdbc) {
|
this.jdbc = jdbc;
|
}
|
|
@Transactional(readOnly = true)
|
public Map<String, Object> detail(Long serviceId) {
|
Map<String, Object> merchant = approvalService(serviceId);
|
Map<String, Object> benefit = benefit();
|
Map<String, Object> result = new LinkedHashMap<>();
|
result.put("benefitId", benefit.get("id"));
|
result.put("serviceId", serviceId);
|
result.put("title", benefit.get("title"));
|
result.put("freeLabel", benefit.get("freeLabel"));
|
// 行政审批详情页顶部直接用商家封面图(后台不再单独配置「详情页图片」);
|
// 商家没配封面时再回落服务权益里的全局图。
|
result.put("heroImage", text(merchant.get("coverUrl"), text(benefit.get("heroImage"))));
|
result.put("heroImages", List.of());
|
result.put("available", number(benefit.get("enabled")) == 1 && number(merchant.get("status")) == 1);
|
result.put("unavailableReason", text(benefit.get("unavailableReason"), "该权益暂未开放"));
|
List<Map<String, Object>> configuredOrganizations = configuredOrganizations(merchant);
|
result.put("organizations", configuredOrganizations.isEmpty()
|
? organizations(((Number) benefit.get("id")).longValue())
|
: configuredOrganizations);
|
return result;
|
}
|
|
private List<Map<String, Object>> configuredOrganizations(Map<String, Object> merchant) {
|
List<Map<String, Object>> items = parseApprovalItems(merchant.get("usageInstructions"));
|
if (items.isEmpty()) {
|
String rightsText = text(merchant.get("rightsText"));
|
if (rightsText.isBlank()) return List.of();
|
items = List.of(Map.of(
|
"name", text(merchant.get("merchantName"), "行政审批服务"),
|
"content", rightsText,
|
"address", text(merchant.get("address")),
|
"phone", text(merchant.get("contactMobile"))));
|
}
|
List<Map<String, Object>> result = new java.util.ArrayList<>();
|
for (int index = 0; index < items.size(); index++) {
|
Map<String, Object> item = items.get(index);
|
Map<String, Object> organization = new LinkedHashMap<>();
|
organization.put("id", merchant.get("id") + "-" + index);
|
organization.put("name", text(item.get("name"), text(merchant.get("merchantName"), "行政审批服务")));
|
organization.put("address", text(item.get("address"), text(merchant.get("address"))));
|
organization.put("latitude", merchant.get("latitude"));
|
organization.put("longitude", merchant.get("longitude"));
|
organization.put("description", text(item.get("content"), text(merchant.get("rightsText"), "暂无权益说明")));
|
organization.put("phone", text(item.get("phone"), text(merchant.get("contactMobile"))));
|
organization.put("officeHours", "");
|
String windowInfoUrl = firstText(item,
|
"windowInfoUrl", "window_info_url", "pdfFile", "pdf_file",
|
"windowInfo", "window_info", "windowFile", "window_file",
|
"fileUrl", "file_url");
|
organization.put("windowInfoUrl", windowInfoUrl);
|
organization.put("windows", List.of());
|
organization.put("hasWindowInfo", !windowInfoUrl.isBlank());
|
result.add(organization);
|
}
|
return result;
|
}
|
|
private List<Map<String, Object>> parseApprovalItems(Object value) {
|
if (value == null || String.valueOf(value).isBlank()) return List.of();
|
try {
|
return OBJECT_MAPPER.readValue(String.valueOf(value), APPROVAL_ITEMS);
|
} catch (Exception ignored) {
|
return List.of();
|
}
|
}
|
|
private List<Map<String, Object>> organizations(Long benefitId) {
|
return query("""
|
select id, organization_name, address, latitude, longitude, rights_text, consultation_phone, office_hours,
|
pdf_file, is_pdf_visible
|
from admin_approval_organization
|
where benefit_id = ? and enabled = 1 and deleted = 0
|
order by sort_no asc, id asc
|
""", benefitId).stream().map(row -> {
|
Long organizationId = ((Number) row.get("id")).longValue();
|
List<Map<String, Object>> windows = query("""
|
select id, window_name, location_text
|
from admin_approval_window
|
where organization_id = ? and enabled = 1 and deleted = 0
|
order by sort_no asc, id asc
|
""", organizationId).stream().map(window -> Map.<String, Object>of(
|
"id", window.get("id"), "name", window.get("windowName"), "location", text(window.get("locationText"))
|
)).toList();
|
Map<String, Object> organization = new LinkedHashMap<>();
|
organization.put("id", organizationId);
|
organization.put("name", row.get("organizationName"));
|
organization.put("address", text(row.get("address")));
|
organization.put("latitude", row.get("latitude"));
|
organization.put("longitude", row.get("longitude"));
|
organization.put("description", row.get("rightsText"));
|
organization.put("phone", text(row.get("consultationPhone")));
|
organization.put("officeHours", text(row.get("officeHours")));
|
String windowInfoUrl = number(row.get("isPdfVisible")) == 1 ? text(row.get("pdfFile")) : "";
|
organization.put("windowInfoUrl", windowInfoUrl);
|
organization.put("windows", windows);
|
organization.put("hasWindowInfo", !windowInfoUrl.isBlank());
|
return organization;
|
}).toList();
|
}
|
|
private Map<String, Object> approvalService(Long serviceId) {
|
if (serviceId == null || serviceId <= 0) throw new BusinessException(ErrorCode.BAD_REQUEST, "行政审批服务信息不能为空");
|
List<Map<String, Object>> rows = query("""
|
select m.id, m.merchant_name, m.address, m.contact_mobile, m.cover_url, m.latitude, m.longitude,
|
m.status, m.usage_instructions, m.rights_text
|
from merchant m
|
where m.id = ? and m.deleted = 0 and m.merchant_type_code = 'approval'
|
""", serviceId);
|
if (rows.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "行政审批服务不存在");
|
return rows.get(0);
|
}
|
|
private Map<String, Object> benefit() {
|
List<Map<String, Object>> rows = query("""
|
select id, title, free_label, hero_image, enabled, unavailable_reason
|
from admin_approval_benefit where deleted = 0
|
order by id asc limit 1
|
""");
|
if (rows.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "行政审批权益暂未配置");
|
return rows.get(0);
|
}
|
|
private List<Map<String, Object>> query(String sql, Object... args) {
|
return DatabaseRows.normalize(jdbc.queryForList(sql, args));
|
}
|
|
private int number(Object value) {
|
return value instanceof Number number ? number.intValue() : Integer.parseInt(String.valueOf(value));
|
}
|
|
private String text(Object value) {
|
return value == null ? "" : String.valueOf(value);
|
}
|
|
private String text(Object value, String fallback) {
|
String valueText = text(value).trim();
|
return valueText.isBlank() ? fallback : valueText;
|
}
|
|
/**
|
* Window PDFs were stored under several names while the admin form was
|
* being rolled out. Keep the portal contract stable by resolving the
|
* first non-empty URL from all supported names (including nested upload
|
* response objects).
|
*/
|
private String firstText(Map<String, Object> source, String... keys) {
|
for (String key : keys) {
|
Object value = source.get(key);
|
String resolved = uploadUrl(value);
|
if (!resolved.isBlank()) return resolved;
|
}
|
return "";
|
}
|
|
@SuppressWarnings("unchecked")
|
private String uploadUrl(Object value) {
|
if (value instanceof Map<?, ?> map) {
|
for (String key : List.of("url", "path", "fileUrl", "file_url", "downloadUrl", "download_url")) {
|
Object nested = map.get(key);
|
if (nested != null) {
|
String resolved = text(nested).trim();
|
if (!resolved.isBlank()) return resolved;
|
}
|
}
|
return "";
|
}
|
return text(value).trim();
|
}
|
}
|