Browse Source

知识库,上传文章时系统自动校验文件名重复项,若存在同名文件,将弹窗展示该文件所属分类位置、当前审核状态,并限制重复上传。

徐滕 2 weeks atrás
parent
commit
6bfe6e5ac3

+ 9 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseShareInfoDao.java

@@ -41,4 +41,13 @@ public interface WorkKnowledgeBaseShareInfoDao extends CrudDao<WorkKnowledgeBase
      * @param id 文件ID
      */
     void incrementClickCount(@org.apache.ibatis.annotations.Param("id") String id);
+
+    /**
+     * 根据文件名称查询重名文件的树节点信息(排除问答答疑分类)
+     * @param name 文件名称
+     * @param excludeId 排除的文件ID(编辑时排除自身)
+     * @return 包含 treeNodeId 和 treeName 的列表
+     */
+    List<Map<String, Object>> findDuplicateFilePaths(@org.apache.ibatis.annotations.Param("name") String name,
+                                                      @org.apache.ibatis.annotations.Param("excludeId") String excludeId);
 }

+ 66 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseShareService.java

@@ -164,6 +164,72 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
     }
 
     /**
+     * 查询同名文件的目录路径及审核状态列表(排除问答答疑分类)
+     * @param name 文件名称
+     * @param excludeId 排除的文件ID(编辑时排除自身)
+     * @return 包含 path(目录路径)和 auditStatus(审核状态值)的列表
+     */
+    public List<Map<String, Object>> findDuplicateFilePaths(String name, String excludeId) {
+        List<Map<String, Object>> duplicates = dao.findDuplicateFilePaths(name, excludeId);
+        List<Map<String, Object>> results = new ArrayList<>();
+        for (Map<String, Object> dup : duplicates) {
+            String treeNodeId = dup.get("treeNodeId") != null ? dup.get("treeNodeId").toString() : null;
+            if (StringUtils.isNotBlank(treeNodeId)) {
+                String path = buildTreePath(treeNodeId);
+                if (StringUtils.isNotBlank(path)) {
+                    // 同一目录路径不重复添加
+                    boolean pathExists = false;
+                    for (Map<String, Object> r : results) {
+                        if (path.equals(r.get("path"))) {
+                            pathExists = true;
+                            break;
+                        }
+                    }
+                    if (!pathExists) {
+                        Map<String, Object> item = new HashMap<>();
+                        item.put("path", path);
+                        Object auditStatusObj = dup.get("auditStatus");
+                        item.put("auditStatus", auditStatusObj != null ? auditStatusObj.toString() : "");
+                        results.add(item);
+                    }
+                }
+            }
+        }
+        return results;
+    }
+
+    /**
+     * 根据树节点ID构建完整目录路径(从根节点到当前节点)
+     */
+    private String buildTreePath(String treeNodeId) {
+        WorkKnowledgeBaseTreeInfo node = treeInfoDao.get(treeNodeId);
+        if (node == null) {
+            return "";
+        }
+        List<String> names = new ArrayList<>();
+        names.add(node.getTreeName());
+        // 通过parent_ids向上追溯祖先节点
+        String parentIds = node.getParentIds();
+        if (StringUtils.isNotBlank(parentIds)) {
+            // parentIds格式: ,rootId,node1,node2,
+            String cleaned = parentIds.replaceAll("^,+", "").replaceAll(",+$", "");
+            if (StringUtils.isNotBlank(cleaned)) {
+                String[] ids = cleaned.split(",");
+                // 从最近的祖先节点向根节点遍历
+                for (int i = ids.length - 1; i >= 0; i--) {
+                    if (StringUtils.isNotBlank(ids[i])) {
+                        WorkKnowledgeBaseTreeInfo ancestor = treeInfoDao.get(ids[i].trim());
+                        if (ancestor != null && StringUtils.isNotBlank(ancestor.getTreeName())) {
+                            names.add(0, ancestor.getTreeName());
+                        }
+                    }
+                }
+            }
+        }
+        return StringUtils.join(names, "-");
+    }
+
+    /**
      * 根据分类名称查询分类列表
      */
     public List<com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgePointCategory> findCategoriesByName(String categoryName) {

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

@@ -880,4 +880,25 @@ public class WorkKnowledgeBaseShareController extends BaseController {
         }
         return result;
     }
+
+    /**
+     * 检查文件名称是否重复(排除问答答疑分类)
+     */
+    @RequiresPermissions("workKnowledgeBase:share:list")
+    @RequestMapping(value = "checkDuplicateName")
+    @ResponseBody
+    public Map<String, Object> checkDuplicateName(@RequestParam String name,
+                                                   @RequestParam(required = false) String excludeId) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            List<Map<String, Object>> duplicates = shareService.findDuplicateFilePaths(name, excludeId);
+            result.put("success", true);
+            result.put("duplicate", !duplicates.isEmpty());
+            result.put("duplicates", duplicates);
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("duplicate", false);
+        }
+        return result;
+    }
 }

+ 19 - 0
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseShareInfoDao.xml

@@ -318,4 +318,23 @@
         WHERE id = #{id} AND del_flag = '0'
     </update>
 
+    <!-- 根据文件名称查询重名文件的树节点信息(排除问答答疑分类) -->
+    <select id="findDuplicateFilePaths" resultType="java.util.HashMap">
+        SELECT DISTINCT
+            a.id AS "fileId",
+            a.audit_status AS "auditStatus",
+            t.id AS "treeNodeId",
+            t.tree_name AS "treeName",
+            t.parent_ids AS "parentIds",
+            t.root_id AS "rootId"
+        FROM work_knowledge_base_share_info a
+        JOIN work_knowledge_base_tree_info t ON a.tree_node_id = t.id AND t.del_flag = '0'
+        WHERE a.name = #{name}
+          AND a.del_flag = '0'
+          AND t.tree_name != '问答答疑'
+          <if test="excludeId != null and excludeId != ''">
+              AND a.id != #{excludeId}
+          </if>
+    </select>
+
 </mapper>

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

@@ -9,8 +9,20 @@
     <script src="${ctxStatic}/common/html/js/script.js"></script>
     <script type="text/javascript">
         var validateForm;
+        var isNameDuplicate = false; // 文件名称是否重复标记
 
         function doSubmit(i) {
+            if (isNameDuplicate) {
+                top.layer.open({
+                    type: 0,
+                    title: '提示',
+                    content: '文件名称已存在重复,请修改后再提交。',
+                    icon: 0,
+                    btn: ['确定'],
+                    offset: 'auto'
+                });
+                return false;
+            }
             if (validateForm.form()) {
                 // 提交前收集动态字段值为JSON
                 collectDynamicValues();
@@ -65,6 +77,51 @@
                 $("input[name='contentAttribute'][value='0']").prop('checked', true);
             }
 
+            // 文件名称失焦时检查是否重复(排除问答答疑分类)
+            var isQaCategory = ${isQaCategory ? 'true' : 'false'};
+            if (!isQaCategory) {
+                // 名称改变时重置重复标记
+                $('input[name="name"]').on('input', function() {
+                    isNameDuplicate = false;
+                });
+
+                $('input[name="name"]').on('blur', function() {
+                    var nameVal = $.trim($(this).val());
+                    if (!nameVal) return;
+                    var excludeId = '${entity.id}';
+                    $.ajax({
+                        type: 'POST',
+                        url: '${ctx}/workKnowledgeBase/share/checkDuplicateName',
+                        data: { name: nameVal, excludeId: excludeId },
+                        dataType: 'json',
+                        success: function(res) {
+                            if (res.success && res.duplicate) {
+                                isNameDuplicate = true;
+                                var auditStatusMap = {'0':'草稿','1':'未审核','2':'审核通过','3':'审核中','5':'审核不通过'};
+                                var detailArr = [];
+                                for (var i = 0; i < res.duplicates.length; i++) {
+                                    var d = res.duplicates[i];
+                                    var statusText = auditStatusMap[d.auditStatus] || '未知';
+                                    detailArr.push(d.path + '(审核状态:' + statusText + ')');
+                                }
+                                var detailStr = detailArr.join('<br/>');
+                                top.layer.open({
+                                    type: 0,
+                                    title: '文件名称重复',
+                                    content: '文件名称已存在,对应文件目录为:<br/>' + detailStr,
+                                    icon: 0,
+                                    btn: ['知道了'],
+                                    offset: 'auto',
+                                    area: ['500px', 'auto']
+                                });
+                            } else {
+                                isNameDuplicate = false;
+                            }
+                        }
+                    });
+                });
+            }
+
             // 初始化动态字段中 Date 类型的 laydate 日期选择器
             layui.use(['form', 'layer', 'laydate'], function () {
                 var form = layui.form;