From 5d34bdd3c426bb2ca5f6627424ae67984f745603 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期三, 21 十月 2026 18:28:59 +0800
Subject: [PATCH] feat: 新增资产/用车/采购模块,完善课题、会员、财务与企微功能

---
 yudao-module-wxcp/src/main/java/cn/iocoder/yudao/module/wxcp/controller/admin/activity/WxCpActivityPublicController.java |  258 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 244 insertions(+), 14 deletions(-)

diff --git a/yudao-module-wxcp/src/main/java/cn/iocoder/yudao/module/wxcp/controller/admin/activity/WxCpActivityPublicController.java b/yudao-module-wxcp/src/main/java/cn/iocoder/yudao/module/wxcp/controller/admin/activity/WxCpActivityPublicController.java
index 6acbdcb..1517cca 100644
--- a/yudao-module-wxcp/src/main/java/cn/iocoder/yudao/module/wxcp/controller/admin/activity/WxCpActivityPublicController.java
+++ b/yudao-module-wxcp/src/main/java/cn/iocoder/yudao/module/wxcp/controller/admin/activity/WxCpActivityPublicController.java
@@ -6,7 +6,9 @@
 import cn.iocoder.yudao.module.system.controller.admin.storage.vo.SystemStorageBlobRespVO;
 import cn.iocoder.yudao.module.wxcp.controller.admin.activity.vo.WxCpSignupPublicReqVO;
 import cn.iocoder.yudao.module.wxcp.dal.dataobject.activity.WxCpActivityDO;
+import cn.iocoder.yudao.module.wxcp.dal.dataobject.activity.WxCpActivityFieldDO;
 import cn.iocoder.yudao.module.wxcp.enums.activity.WxCpActivityStatusEnum;
+import cn.iocoder.yudao.module.wxcp.enums.activity.WxCpActivityTypeEnum;
 import cn.iocoder.yudao.module.wxcp.service.activity.WxCpActivityService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -22,6 +24,7 @@
 import java.net.URI;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
+import java.util.Collections;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -57,9 +60,13 @@
         if (activity == null) {
             return renderMessagePage("娲诲姩涓嶅瓨鍦�", "娲诲姩鍙兘宸茶鍒犻櫎锛岃鑱旂郴娲诲姩鍙戣捣浜虹‘璁ゃ��");
         }
-        if (!isSignupOpen(activity)) {
-            return renderMessagePage("鎶ュ悕宸茬粨鏉�",
-                    "璇ユ椿鍔ㄥ綋鍓嶄笉鍙姤鍚嶏紙鍙兘鏈彂甯冦�佸凡缁撴潫鎴栦笉鍦ㄦ姤鍚嶆椂闂村唴锛夈��");
+        if (!WxCpActivityStatusEnum.PUBLISHED.getStatus().equals(activity.getStatus())) {
+            return renderMessagePage("娲诲姩鏈紑鏀�",
+                    "璇ユ椿鍔ㄥ皻鏈彂甯冿紙鎴栧凡缁撴潫/鍙栨秷锛夛紝璇疯仈绯绘椿鍔ㄥ彂璧蜂汉纭銆�");
+        }
+        // 鍙湁鏁版嵁閲囬泦妯℃澘鏈夎〃鍗曪紱鍏跺畠妯℃澘鍙睍绀鸿鎯呭唴瀹�
+        if (WxCpActivityTypeEnum.needSignup(activity.getActivityType()) && !isInSignupPeriod(activity)) {
+            return renderMessagePage("鎶ュ悕宸茬粨鏉�", "璇ユ椿鍔ㄥ綋鍓嶄笉鍦ㄦ姤鍚嶆椂闂村唴锛岃鑱旂郴娲诲姩鍙戣捣浜虹‘璁ゃ��");
         }
         return renderSignupPage(activity, wxUserId);
     }
@@ -72,12 +79,9 @@
     }
 
     /**
-     * 鎶ュ悕鏄惁寮�鏀撅細娲诲姩闇�涓哄凡鍙戝竷锛屼笖澶勪簬鎶ュ悕鏃堕棿绐楀彛鍐�
+     * 鏄惁澶勪簬鎶ュ悕鏃堕棿绐楀彛鍐�
      */
-    private boolean isSignupOpen(WxCpActivityDO activity) {
-        if (!WxCpActivityStatusEnum.PUBLISHED.getStatus().equals(activity.getStatus())) {
-            return false;
-        }
+    private boolean isInSignupPeriod(WxCpActivityDO activity) {
         LocalDateTime now = LocalDateTime.now();
         if (activity.getSignupStartTime() != null && now.isBefore(activity.getSignupStartTime())) {
             return false;
@@ -96,6 +100,9 @@
                 .append("background:#f5f6f8;color:#1f2329;font-size:15px;line-height:1.6}")
                 .append(".card{background:#fff;border-radius:12px;padding:18px;margin-bottom:12px;box-shadow:0 1px 4px rgba(0,0,0,.06)}")
                 .append(".cover{display:block;width:100%;max-height:260px;object-fit:cover;border-radius:8px;margin-bottom:14px;background:#f2f3f5}")
+                // 璇︽儏鍥惧繀椤绘寜鍘熷浘姣斾緥瀹屾暣灞曠ず锛氫簩缁寸爜/娴锋姤琚杈瑰氨浼氬け鏁堬紝鎵�浠ヨ繖閲屼笉鑳界敤 object-fit:cover
+                .append(".detail-img{display:block;margin:12px 0 0}")
+                .append(".detail-img img{display:block;width:100%;height:auto;border-radius:8px;background:#f2f3f5}")
                 .append("h1{font-size:19px;margin:0 0 14px;font-weight:600;word-break:break-all}")
                 .append(".meta{color:#646a73;font-size:14px}")
                 .append(".meta div{margin-bottom:6px;display:flex}")
@@ -104,8 +111,13 @@
                 .append(".desc{white-space:pre-wrap;word-break:break-word;color:#3f444d}")
                 .append("label{display:block;font-size:14px;color:#646a73;margin:14px 0 6px}")
                 .append("input,textarea{width:100%;padding:11px 12px;border:1px solid #dee0e3;border-radius:8px;font-size:15px;outline:none;background:#fff;font-family:inherit}")
-                .append("input:focus,textarea:focus{border-color:#3370ff}")
+                .append("input:focus,textarea:focus,select:focus{border-color:#3370ff}")
+                .append("select{width:100%;padding:11px 12px;border:1px solid #dee0e3;border-radius:8px;font-size:15px;outline:none;background:#fff;font-family:inherit}")
                 .append("textarea{resize:vertical;min-height:84px}")
+                .append(".file-title{font-weight:600;margin-bottom:8px}")
+                .append(".file-list a{color:#3370ff;text-decoration:none;word-break:break-all}")
+                .append(".choice-row{display:flex;flex-wrap:wrap;gap:14px;margin-top:4px}")
+                .append(".choice{display:inline-flex;align-items:center;gap:5px;margin:0;color:#1f2329;font-size:15px}")
                 .append(".file-row{margin-top:8px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}")
                 .append(".file-btn{display:inline-block;padding:8px 14px;border:1px dashed #c9cdd4;border-radius:8px;color:#3370ff;font-size:14px;background:#fff}")
                 .append(".file-list{margin-top:8px;font-size:13px;color:#646a73;word-break:break-all}")
@@ -148,8 +160,80 @@
         if (StrUtil.isNotBlank(activity.getContent())) {
             sb.append("<div class=\"desc\">").append(esc(activity.getContent())).append("</div>");
         }
+        // 璇︽儏鍥剧墖锛氱揣璺熷湪娲诲姩璇︽儏鏂囧瓧涓嬫柟锛堝悓涓�寮犲崱鐗囧唴锛夛紝鎸夊師鍥炬瘮渚嬪叏瀹藉睍绀猴紝
+        // 鐐逛竴涓嬬敤娴忚鍣ㄦ墦寮�鍘熷浘锛屾柟渚挎垚鍛樻斁澶х湅浜岀淮鐮�/娴锋姤
+        for (String detailImgUrl : resolveDetailImageUrls(activity.getId())) {
+            sb.append("<a class=\"detail-img\" href=\"").append(esc(detailImgUrl))
+                    .append("\" target=\"_blank\" rel=\"noopener\">")
+                    .append("<img src=\"").append(esc(detailImgUrl)).append("\" alt=\"娲诲姩璇︽儏鍥剧墖\">")
+                    .append("</a>");
+        }
         sb.append("</div>");
 
+        // 鍥剧墖閫氱煡妯℃澘锛氬睍绀轰笂浼犵殑鍥剧墖锛屾寜鍘熷浘姣斾緥瀹屾暣灞曠ず
+        appendImageGallery(sb, activity);
+        // 闄勪欢閫氱煡妯℃澘锛氬垪鍑洪檮浠讹紝鎴愬憳鐐瑰紑鍗冲彲涓嬭浇
+        appendFileList(sb, activity);
+
+        // 鍙湁銆屾暟鎹噰闆�/璇勪环銆嶆ā鏉挎墠鏈夊~鍐欒〃鍗�
+        if (WxCpActivityTypeEnum.needSignup(activity.getActivityType())) {
+            appendSignupForm(sb, activity, wxUserId);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 鍥剧墖閫氱煡妯℃澘鐨勫浘鐗囧睍绀哄尯
+     */
+    private void appendImageGallery(StringBuilder sb, WxCpActivityDO activity) {
+        List<SystemStorageBlobRespVO> images = activityService.getActivityImageAttachments(activity.getId());
+        if (CollUtil.isEmpty(images)) {
+            return;
+        }
+        sb.append("<div class=\"card\">");
+        for (SystemStorageBlobRespVO image : images) {
+            String raw = StrUtil.blankToDefault(image.getPreviewURL(), image.getUrl());
+            if (StrUtil.isBlank(raw)) {
+                continue;
+            }
+            String url = toSameOriginUrl(raw);
+            sb.append("<a class=\"detail-img\" href=\"").append(esc(url))
+                    .append("\" target=\"_blank\" rel=\"noopener\">")
+                    .append("<img src=\"").append(esc(url)).append("\" alt=\"娲诲姩鍥剧墖\">")
+                    .append("</a>");
+        }
+        sb.append("</div>");
+    }
+
+    /**
+     * 闄勪欢閫氱煡妯℃澘鐨勯檮浠跺垪琛ㄥ尯
+     */
+    private void appendFileList(StringBuilder sb, WxCpActivityDO activity) {
+        List<SystemStorageBlobRespVO> files = activityService.getActivityFileAttachments(activity.getId());
+        if (CollUtil.isEmpty(files)) {
+            return;
+        }
+        sb.append("<div class=\"card\"><div class=\"file-title\">闄勪欢涓嬭浇</div>")
+                .append("<div class=\"file-list\">");
+        for (SystemStorageBlobRespVO file : files) {
+            String raw = StrUtil.blankToDefault(file.getDownloadURL(),
+                    StrUtil.blankToDefault(file.getUrl(), file.getPreviewURL()));
+            if (StrUtil.isBlank(raw)) {
+                continue;
+            }
+            String url = toSameOriginUrl(raw);
+            String name = StrUtil.blankToDefault(file.getOriginalFilename(),
+                    StrUtil.blankToDefault(file.getName(), "闄勪欢"));
+            sb.append("<div><a href=\"").append(esc(url)).append("\" target=\"_blank\" rel=\"noopener\">")
+                    .append(esc(name)).append("</a></div>");
+        }
+        sb.append("</div></div>");
+    }
+
+    /**
+     * 鏁版嵁閲囬泦/璇勪环妯℃澘鐨勫~鍐欒〃鍗�
+     */
+    private void appendSignupForm(StringBuilder sb, WxCpActivityDO activity, String wxUserId) {
         // 鎶ュ悕琛ㄥ崟锛氬鍚嶃�佹墜鏈哄彿鍧囦负閫夊~锛屽彧濉簡鎵嬫満鍙锋墠鏍¢獙鏍煎紡
         sb.append("<div class=\"card\">")
                 .append("<label>濮撳悕</label>")
@@ -157,13 +241,14 @@
                 .append("<label>鎵嬫満鍙�</label>")
                 .append("<input id=\"mobile\" type=\"tel\" inputmode=\"numeric\" placeholder=\"璇疯緭鍏� 11 浣嶆墜鏈哄彿锛堥�夊~锛塡" maxlength=\"11\" autocomplete=\"tel\">")
                 .append("<label>鍙備笌璇存槑</label>")
-                .append("<textarea id=\"content\" placeholder=\"鍙~鍐欏娉ㄣ�侀渶姹傛垨鍏朵粬璇存槑锛堥�夊~锛塡" maxlength=\"1000\"></textarea>")
-                .append("<label>鍥剧墖 / 闄勪欢</label>")
+                .append("<textarea id=\"content\" placeholder=\"鍙~鍐欏娉ㄣ�侀渶姹傛垨鍏朵粬璇存槑锛堥�夊~锛塡" maxlength=\"1000\"></textarea>");
+        appendCollectFields(sb, activity);
+        sb.append("<label>鍥剧墖 / 闄勪欢</label>")
                 .append("<div class=\"file-row\">")
                 .append("<label class=\"file-btn\" for=\"files\">+ 閫夋嫨鍥剧墖鎴栨枃浠�</label>")
                 .append("<input id=\"files\" type=\"file\" multiple accept=\"image/*,.pdf,.doc,.docx,.xls,.xlsx,.txt\" style=\"display:none\">")
                 .append("</div><div class=\"file-list\" id=\"fileList\"></div>")
-                .append("<button id=\"submit\">鎻愪氦鎶ュ悕</button>")
+                .append("<button id=\"submit\">鎻愪氦</button>")
                 .append("<div class=\"tip\">鎻愪氦鍚庡闇�淇敼锛岃鑱旂郴娲诲姩鍙戣捣浜�</div>")
                 .append("</div><div class=\"toast\" id=\"toast\"></div>");
 
@@ -171,10 +256,27 @@
         sb.append("<script>(function(){")
                 .append("var AID=").append(activity.getId()).append(";")
                 .append("var WXUID=").append(wxUserId == null ? "null" : "\"" + esc(jsStr(wxUserId)) + "\"").append(";")
+                .append("var FIELDS=").append(buildFieldsJson(activity)).append(";")
+                .append("var RATING_ENABLED=").append(Boolean.TRUE.equals(activity.getRatingEnabled())).append(";")
                 .append("var btn=document.getElementById('submit'),toast=document.getElementById('toast');")
                 .append("var fileInput=document.getElementById('files'),fileList=document.getElementById('fileList');")
                 .append("function tip(m){toast.textContent=m;toast.style.display='block';setTimeout(function(){toast.style.display='none'},2200)}")
-                .append("function reset(){btn.disabled=false;btn.textContent='鎻愪氦鎶ュ悕'}")
+                .append("function reset(){btn.disabled=false;btn.textContent='鎻愪氦'}")
+                .append("function collectFields(){")
+                .append("var arr=[],bad=null;")
+                .append("for(var i=0;i<FIELDS.length;i++){var f=FIELDS[i],v='';")
+                .append("if(f.type==='checkbox'){var cs=document.querySelectorAll('input[name=\"f_'+f.id+'\"]:checked'),vs=[];")
+                .append("for(var j=0;j<cs.length;j++){vs.push(cs[j].value)}v=vs.join(',')}")
+                .append("else if(f.type==='radio'){var r=document.querySelector('input[name=\"f_'+f.id+'\"]:checked');v=r?r.value:''}")
+                .append("else{var el=document.getElementById('f_'+f.id);v=el?el.value.trim():''}")
+                .append("if(f.required&&!v){bad=f.label;break}")
+                .append("if(v){arr.push({fieldId:f.id,fieldValue:v})}}")
+                .append("if(bad){tip('銆�'+bad+'銆戜负蹇呭~椤癸紝璇峰~鍐欏悗鍐嶆彁浜�');return null}return arr}")
+                .append("function getRating(){")
+                .append("if(!RATING_ENABLED){return 0}")
+                .append("var r=document.querySelector('input[name=\"rating\"]:checked');")
+                .append("if(!r){tip('璇峰厛瀹屾垚璇勪环鎵撳垎鍚庡啀鎻愪氦');return -1}")
+                .append("return parseInt(r.value,10)}")
                 .append("fileInput.addEventListener('change',function(){")
                 .append("var fs=fileInput.files,h='';")
                 .append("for(var i=0;i<fs.length;i++){h+='<div>路 '+fs[i].name+'</div>'}")
@@ -184,6 +286,8 @@
                 .append("var m=document.getElementById('mobile').value.trim();")
                 .append("var c=document.getElementById('content').value.trim();")
                 .append("if(m&&!/^1[3-9]\\d{9}$/.test(m)){tip('鎵嬫満鍙锋牸寮忎笉姝g‘锛岃濉� 11 浣嶆墜鏈哄彿鎴栫暀绌�');return}")
+                .append("var fv=collectFields();if(fv===null){return}")
+                .append("var rs=getRating();if(rs<0){return}")
                 .append("btn.disabled=true;")
                 .append("var fs=fileInput.files;")
                 .append("var upload=Promise.resolve([]);")
@@ -202,6 +306,8 @@
                 .append("if(c){body.content=c}")
                 .append("if(WXUID){body.wxUserId=WXUID}")
                 .append("if(blobIds.length>0){body.blobIds=blobIds}")
+                .append("if(fv.length>0){body.fieldValues=fv}")
+                .append("if(rs>0){body.ratingScore=rs}")
                 .append("return fetch('signup',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)})")
                 .append(".then(function(r){return r.json()})")
                 .append(".then(function(r){")
@@ -209,7 +315,131 @@
                 .append("else{tip(r.msg||'鎶ュ悕澶辫触');reset()}})}")
                 .append(".catch(function(e){tip((e&&e.message)||'缃戠粶寮傚父锛岃绋嶅悗閲嶈瘯');reset()})")
                 .append("})})();</script></body></html>");
-        return sb.toString();
+    }
+
+    /**
+     * 娓叉煋鏁版嵁閲囬泦妯℃澘鐨勮嚜瀹氫箟瀛楁涓庤瘎浠�
+     */
+    private void appendCollectFields(StringBuilder sb, WxCpActivityDO activity) {
+        String base = "f_";
+        for (WxCpActivityFieldDO field : activityService.getActivityFields(activity.getId())) {
+            String id = base + field.getId();
+            String label = esc(field.getFieldLabel());
+            String required = Boolean.TRUE.equals(field.getRequired()) ? " *" : "";
+            String placeholder = esc(StrUtil.blankToDefault(field.getPlaceholder(),
+                    "璇疯緭鍏�" + field.getFieldLabel()));
+            String type = StrUtil.blankToDefault(field.getFieldType(), WxCpActivityFieldDO.TYPE_TEXT);
+            switch (type) {
+                case WxCpActivityFieldDO.TYPE_TEXTAREA ->
+                        sb.append("<label>").append(label).append(required).append("</label>")
+                                .append("<textarea id=\"").append(id).append("\" placeholder=\"")
+                                .append(placeholder).append("\" maxlength=\"2000\"></textarea>");
+                case WxCpActivityFieldDO.TYPE_NUMBER ->
+                        sb.append("<label>").append(label).append(required).append("</label>")
+                                .append("<input id=\"").append(id)
+                                .append("\" type=\"number\" placeholder=\"").append(placeholder).append("\">");
+                case WxCpActivityFieldDO.TYPE_DATE ->
+                        sb.append("<label>").append(label).append(required).append("</label>")
+                                .append("<input id=\"").append(id).append("\" type=\"date\">");
+                case WxCpActivityFieldDO.TYPE_SELECT -> {
+                    sb.append("<label>").append(label).append(required).append("</label>")
+                            .append("<select id=\"").append(id).append("\"><option value=\"\">璇烽�夋嫨</option>");
+                    for (String option : splitOptions(field.getFieldOptions())) {
+                        sb.append("<option value=\"").append(esc(option)).append("\">")
+                                .append(esc(option)).append("</option>");
+                    }
+                    sb.append("</select>");
+                }
+                case WxCpActivityFieldDO.TYPE_RADIO -> {
+                    sb.append("<label>").append(label).append(required).append("</label><div class=\"choice-row\">");
+                    for (String option : splitOptions(field.getFieldOptions())) {
+                        sb.append("<label class=\"choice\"><input type=\"radio\" name=\"")
+                                .append(id).append("\" value=\"").append(esc(option)).append("\">")
+                                .append(esc(option)).append("</label>");
+                    }
+                    sb.append("</div>");
+                }
+                case WxCpActivityFieldDO.TYPE_CHECKBOX -> {
+                    sb.append("<label>").append(label).append(required).append("</label><div class=\"choice-row\">");
+                    for (String option : splitOptions(field.getFieldOptions())) {
+                        sb.append("<label class=\"choice\"><input type=\"checkbox\" name=\"")
+                                .append(id).append("\" value=\"").append(esc(option)).append("\">")
+                                .append(esc(option)).append("</label>");
+                    }
+                    sb.append("</div>");
+                }
+                case WxCpActivityFieldDO.TYPE_RATING -> {
+                    sb.append("<label>").append(label).append(required).append("</label><div class=\"choice-row\">");
+                    int max = activity.getRatingMax() != null && activity.getRatingMax() > 0 ? activity.getRatingMax() : 5;
+                    for (int i = 1; i <= max; i++) {
+                        sb.append("<label class=\"choice\"><input type=\"radio\" name=\"")
+                                .append(id).append("\" value=\"").append(i).append("\">")
+                                .append(i).append(" 鏄�</label>");
+                    }
+                    sb.append("</div>");
+                }
+                default ->
+                        sb.append("<label>").append(label).append(required).append("</label>")
+                                .append("<input id=\"").append(id).append("\" type=\"text\" placeholder=\"")
+                                .append(placeholder).append("\" maxlength=\"255\">");
+            }
+        }
+        // 鐙珛璇勪环椤癸細寮�鍚悗蹇呴』閫夋嫨鏄熺骇
+        if (Boolean.TRUE.equals(activity.getRatingEnabled())) {
+            int max = activity.getRatingMax() != null && activity.getRatingMax() > 0
+                    ? activity.getRatingMax() : 5;
+            sb.append("<label>").append(esc(StrUtil.blankToDefault(activity.getRatingTitle(), "娲诲姩璇勪环")))
+                    .append(" *</label><div class=\"choice-row\">");
+            for (int i = 1; i <= max; i++) {
+                sb.append("<label class=\"choice\"><input type=\"radio\" name=\"rating\" value=\"")
+                        .append(i).append("\">").append(i).append(" 鏄�</label>");
+            }
+            sb.append("</div>");
+        }
+    }
+
+    private List<String> splitOptions(String options) {
+        if (StrUtil.isBlank(options)) {
+            return Collections.emptyList();
+        }
+        return StrUtil.split(options, ',', true, true);
+    }
+
+    /**
+     * 鎶婅嚜瀹氫箟瀛楁瀹氫箟杞垚鍓嶇鎻愪氦鑴氭湰鍙敤鐨� JSON
+     */
+    private String buildFieldsJson(WxCpActivityDO activity) {
+        List<WxCpActivityFieldDO> fields = activityService.getActivityFields(activity.getId());
+        StringBuilder json = new StringBuilder("[");
+        for (int i = 0; i < fields.size(); i++) {
+            WxCpActivityFieldDO field = fields.get(i);
+            if (i > 0) {
+                json.append(',');
+            }
+            json.append("{\"id\":").append(field.getId())
+                    .append(",\"label\":\"").append(esc(jsStr(field.getFieldLabel()))).append("\"")
+                    .append(",\"type\":\"").append(esc(jsStr(field.getFieldType()))).append("\"")
+                    .append(",\"required\":").append(Boolean.TRUE.equals(field.getRequired())).append('}');
+        }
+        return json.append(']').toString();
+    }
+
+    /**
+     * 鍙栨椿鍔ㄨ鎯呭浘鐗囧湴鍧�鍒楄〃锛堟寜涓婁紶鍏堝悗鎺掑簭锛屽湴鍧�鍚屾牱杞垚鍚屾簮鐩稿璺緞锛�
+     *
+     * 涓庡皝闈㈠垎寮�鍙栵細灏侀潰鎸� 16:9 瑁佸壀灞曠ず锛岃鎯呭浘鎸夊師鍥炬瘮渚嬪畬鏁村睍绀猴紝
+     * 浜岀淮鐮佽繖绫讳笉鑳借鐨勫浘瑕佹斁璇︽儏鍥鹃噷銆�
+     */
+    private List<String> resolveDetailImageUrls(Long activityId) {
+        List<SystemStorageBlobRespVO> attachments = activityService.getActivityDetailAttachments(activityId);
+        if (CollUtil.isEmpty(attachments)) {
+            return Collections.emptyList();
+        }
+        return attachments.stream()
+                .map(attachment -> StrUtil.blankToDefault(attachment.getPreviewURL(), attachment.getUrl()))
+                .filter(StrUtil::isNotBlank)
+                .map(this::toSameOriginUrl)
+                .toList();
     }
 
     /**

--
Gitblit v1.9.3