Explorar el Código

知识库,界面展示模块,文件展示模块

徐滕 hace 1 semana
padre
commit
10fc4acc38

+ 47 - 5
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseShareService.java

@@ -273,7 +273,9 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
             for (Map<String, Object> map : list) {
                 map.put("uploadMode", entity.getUploadMode());
             }
-            // 处理附件url
+            // 处理附件url:从 work_attachment 表批量加载第一个附件的信息,替代原有 file_url 字段
+            fillFirstAttachmentData(list);
+            // 处理附件url(添加域名前缀、生成临时预览URL)
             workattachmentService.attachmentManageByUrlOnWorkKnowledgeBaseShare(list);
 
             // 标记当前登录用户是否已对列表中的文件审核过
@@ -359,7 +361,7 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
     public void saveShare(WorkKnowledgeBaseShareInfo shareInfo) {
         boolean isNew = shareInfo.getIsNewRecord();
 
-        // 从附件列表中提前提取第一个有效附件的 url,写入 file_url 字段
+        // 附件URL预处理(不再写入file_url字段,附件数据统一存储在work_attachment表中)
         List<Workattachment> attachments = shareInfo.getWorkAttachments();
         if (attachments != null) {
             for (Workattachment attachment : attachments) {
@@ -368,9 +370,6 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
                         && StringUtils.isNotBlank(attachment.getUrl())) {
                     String url = workattachmentService.disposeUrl(attachment);
                     attachment.setUrl(url);
-                    shareInfo.setFileUrl(attachment.getUrl());
-                    shareInfo.setFileName(attachment.getAttachmentName() != null ? attachment.getAttachmentName() : "");
-                    break;
                 }
             }
         }
@@ -700,6 +699,41 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
     }
 
     /**
+     * 批量填充每行数据的第一个附件信息(替代原有 file_url/file_name 字段)
+     * 从 work_attachment 表查询每个文件对应的第一个附件,将 url 和 attachmentName 写入 map
+     * @param list 查询结果列表(每行为 Map,包含 id 字段)
+     */
+    public void fillFirstAttachmentData(List<Map<String, Object>> list) {
+        if (list == null || list.isEmpty()) {
+            return;
+        }
+        for (Map<String, Object> map : list) {
+            Object id = map.get("id");
+            if (id == null) continue;
+            String fileId = id.toString();
+            List<Workattachment> attList = workattachmentService.getListByAttachmentIdAndFlag(fileId, ATTACHMENT_FLAG);
+            if (attList != null && !attList.isEmpty()) {
+                Workattachment firstAttach = attList.get(0);
+                map.put("fileUrl", firstAttach.getUrl());
+                map.put("fileName", firstAttach.getAttachmentName());
+                // 附件数量
+                map.put("attachmentCount", attList.size());
+                // 所有附件名称逗号分隔展示
+                StringBuilder namesBuilder = new StringBuilder();
+                for (int i = 0; i < attList.size(); i++) {
+                    if (i > 0) namesBuilder.append(", ");
+                    String name = attList.get(i).getAttachmentName();
+                    namesBuilder.append(name != null ? name : "");
+                }
+                map.put("allAttachmentNames", namesBuilder.toString());
+            } else {
+                map.put("attachmentCount", 0);
+                map.put("allAttachmentNames", "");
+            }
+        }
+    }
+
+    /**
      * 发起审核:未审核(1) -> 审核中(2),清空通过/驳回统计
      */
     @Transactional(readOnly = false)
@@ -1773,6 +1807,14 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
         delVal.setFileId(entity.getId());
         delVal.preUpdate();
         dynamicValueInfoDao.deleteByFileId(delVal);
+
+        // 同步逻辑删除关联的附件记录
+        List<Workattachment> attachments = workattachmentService.getListByAttachmentIdAndFlag(entity.getId(), ATTACHMENT_FLAG);
+        if (attachments != null) {
+            for (Workattachment attachment : attachments) {
+                workattachmentService.delete(attachment);
+            }
+        }
     }
 
     /**

+ 50 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseShareController.java

@@ -408,6 +408,23 @@ public class WorkKnowledgeBaseShareController extends BaseController {
             shareInfo.setWorkAttachments(shareService.findAttachmentsByFileId(shareInfo.getId()));
         }
 
+        // 编辑时回显主审专家姓名(expertReviewerNames 为非数据库字段,需根据ID反查)
+        if (StringUtils.isNotBlank(shareInfo.getExpertReviewerIds())) {
+            StringBuilder namesBuilder = new StringBuilder();
+            for (String eid : shareInfo.getExpertReviewerIds().split(",")) {
+                if (StringUtils.isNotBlank(eid)) {
+                    com.jeeplus.modules.sys.entity.User expertUser = UserUtils.get(eid.trim());
+                    if (expertUser != null && StringUtils.isNotBlank(expertUser.getName())) {
+                        if (namesBuilder.length() > 0) {
+                            namesBuilder.append(",");
+                        }
+                        namesBuilder.append(expertUser.getName());
+                    }
+                }
+            }
+            shareInfo.setExpertReviewerNames(namesBuilder.toString());
+        }
+
         // 判断是否为问答答疑分类
         boolean isQaCategory = false;
         String treeName = null;
@@ -628,6 +645,36 @@ public class WorkKnowledgeBaseShareController extends BaseController {
     }
 
     /**
+     * 获取文件的所有附件列表(JSON接口,用于多文件弹窗展示)
+     */
+    @RequiresPermissions(value = {"workKnowledgeBase:share:view", "workKnowledgeBase:share:edit"}, logical = org.apache.shiro.authz.annotation.Logical.OR)
+    @RequestMapping(value = "getAttachmentList")
+    @ResponseBody
+    public Map<String, Object> getAttachmentList(@RequestParam String fileId) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            List<com.jeeplus.modules.sys.entity.Workattachment> attachments = shareService.findAttachmentsByFileId(fileId);
+            List<Map<String, String>> attachList = new ArrayList<>();
+            if (attachments != null) {
+                for (com.jeeplus.modules.sys.entity.Workattachment att : attachments) {
+                    Map<String, String> item = new HashMap<>();
+                    item.put("name", att.getAttachmentName() != null ? att.getAttachmentName() : "");
+                    item.put("url", att.getUrl() != null ? att.getUrl() : "");
+                    item.put("temporaryUrl", att.getTemporaryUrl() != null ? att.getTemporaryUrl() : "");
+                    item.put("createDate", att.getCreateDate() != null ? com.jeeplus.common.utils.DateUtils.formatDateTime(att.getCreateDate()) : "");
+                    attachList.add(item);
+                }
+            }
+            result.put("success", true);
+            result.put("data", attachList);
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", e.getMessage());
+        }
+        return result;
+    }
+
+    /**
      * 导出导入模板(根据rootId动态生成)
      */
     @RequiresPermissions("workKnowledgeBase:share:import")
@@ -763,6 +810,9 @@ public class WorkKnowledgeBaseShareController extends BaseController {
                 }
                 List<Map<String, Object>> dataList = shareService.findDynamicListAll(queryEntity, rootDynamicFields, dynamicConditions);
 
+                // 从 work_attachment 表加载第一个附件信息(替代原有 file_url/file_name 字段)
+                shareService.fillFirstAttachmentData(dataList);
+
                 // 处理导出数据
                 List<Map<String, Object>> exportData = new ArrayList<>();
                 int rowNum = 1;

+ 14 - 20
src/main/webapp/WEB-INF/tags/table/singleAttachmentManager.tag

@@ -4,7 +4,7 @@
 <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
 <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
 
-<%-- 单文件上传组件:最多上传1个文件,去除收藏调用功能 --%>
+<%-- 多文件上传组件:支持上传多个文件 --%>
 
 <%-- 可配置参数定义 --%>
 <%@ attribute name="title" type="java.lang.String" description="附件区域标题"%>
@@ -37,10 +37,10 @@
     <%-- 标题区域 --%>
     <div class="form-group-label"><h2>${title}<span style="color: red;font-size: 14px;">${titleDescribe}</span></h2></div>
 
-    <%-- 上传按钮区域(已有1个附件时隐藏) --%>
+    <%-- 上传按钮区域 --%>
     <div class="layui-item nav-btns">
         <a id="${baseId}_btn" class="nav-btn nav-btn-add" title="${addBtnText}"
-           style="font-size:14px;<c:if test="${attachmentCount >= 1}">display:none;</c:if>">
+           style="font-size:14px;">
             <i class="fa fa-plus"></i>&nbsp;${addBtnText}
         </a>
     </div>
@@ -54,11 +54,12 @@
         </div>
     </div>
 
-    <%-- 文件选择框(隐藏,通过上传按钮触发,允许多选) --%>
+    <%-- 文件选择框(隐藏,通过上传按钮触发,允许多选) --%>
     <input
             id="${baseId}_file"
             type="file"
             name="${baseId}_file"
+            multiple
             style="display: none;"
             onChange="if(this.value)${fileHandlerFuncName}(this.value);"
     />
@@ -229,15 +230,13 @@
         document.getElementById('${baseId}_file').click();
     });
 
-    // 单文件上传处理函数(最多1个文件)
+    // 多文件上传处理函数
     function ${fileHandlerFuncName}(tValue) {
         var existCount = document.getElementById('file_${baseId}').rows.length;
         var fileInput = document.getElementById('${baseId}_file');
         var files = fileInput.files;
 
-        if (existCount >= 1) {
-            layer.msg('最多只能上传1个文件,请删除现有文件后再上传。', {icon: 2});
-            fileInput.value = '';
+        if (files.length === 0) {
             return;
         }
 
@@ -250,27 +249,22 @@
             var file = files[i];
             var attachmentId = '';
             document.getElementById('addFile' + divId).style.display = 'block';
-            multipartUploadWithStsOnFileSize(storeAs, file, attachmentId, attachmentFlag, uploadPath, divId, existCount);
+            multipartUploadWithStsOnFileSize(storeAs, file, attachmentId, attachmentFlag, uploadPath, divId, existCount + i);
         }
 
         // 上传后延迟检查按钮状态
         setTimeout(function() {
-            checkSingleUploadBtn_${baseId}();
+            checkUploadBtn_${baseId}();
         }, 1500);
     }
 
-    // 检查并控制上传按钮显示状态
-    function checkSingleUploadBtn_${baseId}() {
-        var existCount = document.getElementById('file_${baseId}').rows.length;
+    // 检查上传按钮显示状态
+    function checkUploadBtn_${baseId}() {
         var btn = document.getElementById('${baseId}_btn');
-        if (existCount >= 1) {
-            btn.style.display = 'none';
-        } else {
-            btn.style.display = '';
-        }
+        btn.style.display = '';
     }
 
-    // 监听删除按钮,删除后重新显示上传按钮
+    // 监听删除按钮
     (function() {
         var tbody = document.getElementById('file_${baseId}');
         tbody.addEventListener('click', function(e) {
@@ -279,7 +273,7 @@
             while (target && target !== tbody) {
                 if (target.classList && target.classList.contains('op-btn-delete')) {
                     setTimeout(function() {
-                        checkSingleUploadBtn_${baseId}();
+                        checkUploadBtn_${baseId}();
                     }, 500);
                     break;
                 }

+ 1 - 1
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareForm.jsp

@@ -371,7 +371,7 @@
 
 
 
-            <!-- 文件上传区域(单文件上传,最多1个) -->
+            <!-- 文件上传区域(支持多文件上传) -->
             <table:singleAttachmentManager
                     title="附件上传"
                     addBtnText="上传文件"

+ 65 - 1
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareList.jsp

@@ -239,6 +239,59 @@
             });
         }
 
+        /** 多文件弹窗:展示所有附件列表 */
+        function showAttachmentList(fileId) {
+            layer.open({
+                type: 1,
+                area: ['550px', '400px'],
+                title: '附件列表',
+                content: '<div style="padding:15px;"><table id="attachmentListTable" class="table table-bordered" style="margin:0;"><thead><tr><th>文件名</th><th width="150">上传时间</th></tr></thead><tbody><tr><td colspan="2" style="text-align:center;">加载中...</td></tr></tbody></table></div>',
+                btn: ['关闭'],
+                success: function(layero, index) {
+                    $.ajax({
+                        type: 'GET',
+                        url: '${ctx}/workKnowledgeBase/share/getAttachmentList',
+                        data: { fileId: fileId },
+                        success: function(result) {
+                            if (result.success && result.data && result.data.length > 0) {
+                                var tbody = '';
+                                for (var i = 0; i < result.data.length; i++) {
+                                    var att = result.data[i];
+                                    var previewUrl = att.temporaryUrl || att.url || '';
+                                    var fileName = att.name || '';
+                                    var createDate = att.createDate || '';
+                                    tbody += '<tr>';
+                                    tbody += '<td style="word-break:break-all;cursor:pointer;color:#1e9fff;text-align:center;" onclick="openPreviewAttachment(\'' + previewUrl.replace(/'/g, "\\'") + '\', \'' + fileName.replace(/'/g, "\\'") + '\')" title="点击查看详情">' + fileName + '</td>';
+                                    tbody += '<td style="text-align:center;">' + createDate + '</td>';
+                                    tbody += '</tr>';
+                                }
+                                $(layero).find('tbody').html(tbody);
+                            } else {
+                                $(layero).find('tbody').html('<tr><td colspan="2" style="text-align:center;">暂无附件</td></tr>');
+                            }
+                        },
+                        error: function() {
+                            $(layero).find('tbody').html('<tr><td colspan="2" style="text-align:center;color:red;">加载失败</td></tr>');
+                        }
+                    });
+                },
+                btn1: function(index) { layer.close(index); }
+            });
+        }
+
+        /** 从附件弹窗中打开文件预览 */
+        function openPreviewAttachment(url, fileName) {
+            if (!url) return;
+            var name = (fileName || '').toLowerCase();
+            if (name.indexOf('jpg') != -1 || name.indexOf('png') != -1 || name.indexOf('gif') != -1 || name.indexOf('jpeg') != -1 || name.indexOf('bmp') != -1) {
+                openPreview(url, 5);
+            } else if (name.indexOf('pdf') != -1) {
+                openPreview(url, 1);
+            } else {
+                openPreview(url, 2);
+            }
+        }
+
         /** 审核详情弹窗(三按钮:通过/驳回/关闭) */
         function openAuditDetailDialog(id) {
             if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {
@@ -868,6 +921,15 @@
                 }
             }},
             {field: 'fileUrl', align: 'center', title: '文件地址', minWidth: 200, templet: function(d) {
+                // 多文件:逗号分隔展示文件名,点击弹出文件列表
+                if (d.attachmentCount > 1) {
+                    var displayName = d.allAttachmentNames || '';
+                    if (displayName.length > 40) {
+                        displayName = displayName.substring(0, 40) + '...';
+                    }
+                    return '<a href="javascript:void(0)" class="attention-info" onclick="showAttachmentList(\'' + d.id + '\')" title="' + (d.allAttachmentNames || '') + '">' + displayName + '</a>';
+                }
+                // 单文件:原有逻辑不变
                 if(2 == d.uploadMode){
                     if(d.fileName.toLowerCase().indexOf('jpg') != -1 || d.fileName.toLowerCase().indexOf('png') != -1 || d.fileName.toLowerCase().indexOf('gif') != -1 || d.fileName.toLowerCase().indexOf('bmp') != -1 || d.fileName.toLowerCase().indexOf('jpeg') != -1){
                         return "<img src="+d.temporaryUrl+" width='50' height='50' onclick=\"openDialogView('预览','${ctx}/sys/picturepreview/picturePreview?url=" + d.temporaryUrl +"','90%','90%')\" alt='"+d.fileName+"'>";
@@ -1019,7 +1081,7 @@
                 }
 
                 //添加手动赋分功能(主要是为了有些文章不适合审批,上传人可能都不是文档原创的本人。上传之后,由具有相关权限的人直接进行赋分,赋分后文档相当于直接审核通过)
-                <shiro:hasPermission name="workKnowledgeBase:share:audit">
+                <shiro:hasPermission name="workKnowledgeBase:share:manualScoring">
                 if (d.canManualScore === '1' && d.auditStatus !== 5 && !d.isQaCategory) {
                     xml += '<a href="javascript:void(0)" onclick="openManualScoreDialog(\'' + d.id + '\')" class="layui-btn layui-btn-xs layui-bg-green"> 手动赋分</a>';
                 }
@@ -1050,6 +1112,8 @@
                     ,"temporaryUrl": "<c:out value='${row.temporaryUrl}'/>"
                     ,"uploadMode": "<c:out value='${row.uploadMode}'/>"
                     ,"fileUrl": "<c:out value='${row.fileUrl}'/>"
+                    ,"attachmentCount": ${row.attachmentCount != null ? row.attachmentCount : 0}
+                    ,"allAttachmentNames": "<c:out value='${row.allAttachmentNames}'/>"
                     ,"createTime": "${row.createTime}"
                     ,"createByName": "${row.createByName}"
                     ,"userid": "${fns:getUser().id}"