shinnosuke
2026-09-21 7844f5af457ff3b7d3f8eeac8799e8d281e635a1
talent-card-server/src/main/java/com/talentcard/server/business/portal/MedicalPackagePortalService.java
@@ -46,7 +46,12 @@
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("packageId", row.get("packageId"));
        result.put("name", row.get("packageName"));
        result.put("heroImage", row.get("heroImage"));
        result.put("heroImage", detailHeroImage(row));
        // 商户在「图文详情」里可以传多张:顶部大图取第一张,剩下的(含第一张)在这里整组返回,
        // 详情页按顺序铺出来,否则商户传了几张也只能看到一张。
        result.put("detailImages", imageUrls(row.get("productImages")).stream()
                .filter(url -> !url.isBlank())
                .toList());
        result.put("free", number(row.get("freeStatus")) == 1);
        result.put("freeLabel", number(row.get("freeStatus")) == 1 ? "免费" : "优惠");
        result.put("applicableCards", row.get("applicableCards"));
@@ -99,6 +104,7 @@
        if (packageId == null || packageId <= 0) throw new BusinessException(ErrorCode.BAD_REQUEST, "体检套餐信息不能为空");
        List<Map<String, Object>> rows = query("""
                select p.id as package_id, p.merchant_id, p.product_name as package_name, p.cover_url as hero_image,
                       p.product_images as product_images,
                       case when coalesce(p.sale_price, 0) = 0 then 1 else 0 end as free_status,
                       '' as applicable_cards,
                       coalesce(
@@ -117,6 +123,33 @@
        return rows.get(0);
    }
    /**
     * 详情页大图:优先用商户在「商品详情 → 图文详情」上传的第一张图({@code product_images}),
     * 没配时才回落商品封面图。
     *
     * <p>图文详情才是商户为详情页配的图,封面图只是列表里的缩略图。详情页直接取封面,
     * 商户改了图文详情也看不到任何变化,表现成"详情图片没生效"。
     */
    private String detailHeroImage(Map<String, Object> row) {
        for (String image : imageUrls(row.get("productImages"))) {
            if (!image.isBlank()) return image;
        }
        return text(row.get("heroImage"));
    }
    /** {@code product_images} 是 json 数组列(驱动按字符串返回);内容不是数组或格式坏掉时按"没配"处理。 */
    private List<String> imageUrls(Object value) {
        String json = text(value).trim();
        if (!json.startsWith("[")) return List.of();
        try {
            List<String> parsed = JSON.parseArray(json, String.class);
            if (parsed == null) return List.of();
            return parsed.stream().map(item -> item == null ? "" : item.trim()).toList();
        } catch (RuntimeException ignored) {
            return List.of();
        }
    }
    private Map<String, Object> packageListView(Map<String, Object> row) {
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("id", row.get("id"));