Explorar el Código

知识库功能

徐滕 hace 3 días
padre
commit
2f98753543
Se han modificado 24 ficheros con 1051 adiciones y 47 borrados
  1. 16 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseTreeInfoDao.java
  2. 227 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseImportInfo.java
  3. 21 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseTreeInfo.java
  4. 112 3
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseShareService.java
  5. 85 11
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseTreeService.java
  6. 37 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseShareController.java
  7. 51 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseTreeController.java
  8. 3 0
      src/main/java/com/jeeplus/modules/knowledgeSharing/dify/KnowledgeDifyController.java
  9. 3 4
      src/main/java/com/jeeplus/modules/knowledgeSharing/web/KnowledgeBaseController.java
  10. 6 0
      src/main/java/com/jeeplus/modules/workstaff/dao/WorkStaffCertificateDao.java
  11. 71 8
      src/main/java/com/jeeplus/modules/workstaff/service/WorkStaffCertificateService.java
  12. 1 0
      src/main/java/com/jeeplus/modules/workstaff/utils/PdfSignUtil.java
  13. 4 3
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseShareInfoDao.xml
  14. 47 5
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseTreeInfoDao.xml
  15. 15 0
      src/main/resources/mappings/modules/workstaff/WorkStaffCertificateDao.xml
  16. 67 4
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseIndex.jsp
  17. 2 2
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareDetail.jsp
  18. 2 2
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareForm.jsp
  19. 94 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareImport.jsp
  20. 36 3
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareList.jsp
  21. 90 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseTreeExplainForm.jsp
  22. 59 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseTreeExplainView.jsp
  23. 1 1
      src/main/webapp/webpage/modules/workstaff/workStaffBasicCertificateModify.jsp
  24. 1 1
      src/main/webapp/webpage/modules/workstaff/workStaffBasicDetailModify.jsp

+ 16 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseTreeInfoDao.java

@@ -3,6 +3,7 @@ package com.jeeplus.modules.WorkKnowledgeBase.dao;
 import com.jeeplus.common.persistence.CrudDao;
 import com.jeeplus.common.persistence.annotation.MyBatisDao;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -28,4 +29,19 @@ public interface WorkKnowledgeBaseTreeInfoDao extends CrudDao<WorkKnowledgeBaseT
      * 逻辑删除(含子节点)
      */
     void deleteByLogicWithChildren(WorkKnowledgeBaseTreeInfo entity);
+
+    /**
+     * 单独更新 explain 字段
+     */
+    void updateExplain(WorkKnowledgeBaseTreeInfo entity);
+
+    /**
+     * 根据节点名称精确查找节点id
+     */
+    String findIdByTreeName(@Param("treeName") String treeName);
+
+    /**
+     * 查询所有根节点(parent_id='0'的节点)
+     */
+    List<WorkKnowledgeBaseTreeInfo> findRootNodes();
 }

+ 227 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseImportInfo.java

@@ -0,0 +1,227 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+import com.jeeplus.common.utils.excel.annotation.ExcelField;
+
+import java.util.Date;
+
+/**
+ * 知识库-文件信息表实体(公共字段)
+ * @author: 徐滕
+ * @version: 2026-04-22
+ */
+public class WorkKnowledgeBaseImportInfo extends DataEntity<WorkKnowledgeBaseImportInfo> {
+
+    /**
+     * 序号
+     */
+    private String index;
+
+    /**
+     * 标准体系表编号
+     */
+    private String standardSystemCode;
+
+    /**
+     * 标准名称
+     */
+    private String standardName;
+
+    /**
+     * 标准号或文号
+     */
+    private String standardNoOrDocumentNo;
+
+    /**
+     * 转发文号
+     */
+    private String transmitDocumentNo;
+
+    /**
+     * 发布部门
+     */
+    private String publishDepartment;
+
+    /**
+     * 实施日期
+     */
+    private Date effectiveDate;
+
+    /**
+     * 标准级别
+     */
+    private String standardLevel;
+
+    /**
+     * 电压等级
+     */
+    private String voltageLevel;
+
+    /**
+     * 工程类型
+     */
+    private String projectType;
+
+    /**
+     * 编制状态
+     */
+    private String compileStatus;
+
+    /**
+     * 被代替标准编号及名称
+     */
+    private String replacedStandardNoAndName;
+
+    /**
+     * 国家、行业、企业标准关系
+     */
+    private String standardRelation;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 所属节点名称
+     */
+    private String systemNodeName;
+
+    // 以下为 Getter / Setter 方法
+
+
+    @ExcelField(title="序号", align=2, sort=1)
+    public String getIndex() {
+        return index;
+    }
+
+    public void setIndex(String index) {
+        this.index = index;
+    }
+
+    @ExcelField(title="标准体系表编号", align=2, sort=2)
+    public String getStandardSystemCode() {
+        return standardSystemCode;
+    }
+
+    public void setStandardSystemCode(String standardSystemCode) {
+        this.standardSystemCode = standardSystemCode;
+    }
+
+    @ExcelField(title="标准名称", align=2, sort=3)
+    public String getStandardName() {
+        return standardName;
+    }
+
+    public void setStandardName(String standardName) {
+        this.standardName = standardName;
+    }
+
+    @ExcelField(title="标准号或文号", align=2, sort=4)
+    public String getStandardNoOrDocumentNo() {
+        return standardNoOrDocumentNo;
+    }
+
+    public void setStandardNoOrDocumentNo(String standardNoOrDocumentNo) {
+        this.standardNoOrDocumentNo = standardNoOrDocumentNo;
+    }
+
+    @ExcelField(title="转发文号", align=2, sort=5)
+    public String getTransmitDocumentNo() {
+        return transmitDocumentNo;
+    }
+
+    public void setTransmitDocumentNo(String transmitDocumentNo) {
+        this.transmitDocumentNo = transmitDocumentNo;
+    }
+
+    @ExcelField(title="发布部门", align=2, sort=6)
+    public String getPublishDepartment() {
+        return publishDepartment;
+    }
+
+    public void setPublishDepartment(String publishDepartment) {
+        this.publishDepartment = publishDepartment;
+    }
+
+    @ExcelField(title="实施日期", align=2, sort=7)
+    public Date getEffectiveDate() {
+        return effectiveDate;
+    }
+
+    public void setEffectiveDate(Date effectiveDate) {
+        this.effectiveDate = effectiveDate;
+    }
+
+    @ExcelField(title="标准级别", align=2, sort=8)
+    public String getStandardLevel() {
+        return standardLevel;
+    }
+
+    public void setStandardLevel(String standardLevel) {
+        this.standardLevel = standardLevel;
+    }
+
+    @ExcelField(title="电压等级", align=2, sort=9)
+    public String getVoltageLevel() {
+        return voltageLevel;
+    }
+
+    public void setVoltageLevel(String voltageLevel) {
+        this.voltageLevel = voltageLevel;
+    }
+
+    @ExcelField(title="工程类型", align=2, sort=10)
+    public String getProjectType() {
+        return projectType;
+    }
+
+    public void setProjectType(String projectType) {
+        this.projectType = projectType;
+    }
+
+    @ExcelField(title="编制状态", align=2, sort=11)
+    public String getCompileStatus() {
+        return compileStatus;
+    }
+
+    public void setCompileStatus(String compileStatus) {
+        this.compileStatus = compileStatus;
+    }
+
+    @ExcelField(title="被代替标准编号及名称", align=2, sort=12)
+    public String getReplacedStandardNoAndName() {
+        return replacedStandardNoAndName;
+    }
+
+    public void setReplacedStandardNoAndName(String replacedStandardNoAndName) {
+        this.replacedStandardNoAndName = replacedStandardNoAndName;
+    }
+
+    @ExcelField(title="国家、行业、企业标准关系", align=2, sort=13)
+    public String getStandardRelation() {
+        return standardRelation;
+    }
+
+    public void setStandardRelation(String standardRelation) {
+        this.standardRelation = standardRelation;
+    }
+
+    @ExcelField(title="备注", align=2, sort=14)
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    @ExcelField(title="所属节点名称", align=2, sort=15)
+    public String getSystemNodeName() {
+        return systemNodeName;
+    }
+
+    public void setSystemNodeName(String systemNodeName) {
+        this.systemNodeName = systemNodeName;
+    }
+}

+ 21 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseTreeInfo.java

@@ -1,6 +1,7 @@
 package com.jeeplus.modules.WorkKnowledgeBase.entity;
 
 import com.jeeplus.common.persistence.DataEntity;
+import com.jeeplus.modules.sys.entity.Workattachment;
 
 import java.util.List;
 
@@ -16,6 +17,7 @@ public class WorkKnowledgeBaseTreeInfo extends DataEntity<WorkKnowledgeBaseTreeI
     private String rootId;         // 根节点id
     private String treeName;       // 节点名称
     private Integer sort;          // 排序
+    private String explain;        // 类型描述(富文本,TEXT格式)
 
     /** 父节点名称(用于回显) */
     private String parentName;
@@ -26,6 +28,9 @@ public class WorkKnowledgeBaseTreeInfo extends DataEntity<WorkKnowledgeBaseTreeI
     /** 子节点列表(树形展示用) */
     private List<WorkKnowledgeBaseTreeInfo> children;
 
+    /** 附件列表 */
+    private List<Workattachment> workAttachments;
+
     public String getParentId() {
         return parentId;
     }
@@ -89,4 +94,20 @@ public class WorkKnowledgeBaseTreeInfo extends DataEntity<WorkKnowledgeBaseTreeI
     public void setChildren(List<WorkKnowledgeBaseTreeInfo> children) {
         this.children = children;
     }
+
+    public String getExplain() {
+        return explain;
+    }
+
+    public void setExplain(String explain) {
+        this.explain = explain;
+    }
+
+    public List<Workattachment> getWorkAttachments() {
+        return workAttachments;
+    }
+
+    public void setWorkAttachments(List<Workattachment> workAttachments) {
+        this.workAttachments = workAttachments;
+    }
 }

+ 112 - 3
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseShareService.java

@@ -8,9 +8,7 @@ import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseDynamicInfoDao
 import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseDynamicValueInfoDao;
 import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseShareInfoDao;
 import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseTreeInfoDao;
-import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo;
-import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicValueInfo;
-import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseShareInfo;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.*;
 import com.jeeplus.modules.sys.entity.Workattachment;
 import com.jeeplus.modules.sys.service.WorkattachmentService;
 import com.jeeplus.modules.sys.utils.UserUtils;
@@ -108,6 +106,7 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
             for (Map<String, Object> map : list) {
                 map.put("uploadMode", entity.getUploadMode());
             }
+            // 处理附件url
             workattachmentService.attachmentManageByUrlOnWorkKnowledgeBaseShare(list);
             page.setList(list);
         } else {
@@ -220,4 +219,114 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
     public String getRootIdByNodeId(String nodeId) {
         return treeInfoDao.getRootIdByNodeId(nodeId);
     }
+
+    /**
+     * 查询所有根节点(parent_id='0'的节点)
+     */
+    public List<WorkKnowledgeBaseTreeInfo> findRootNodes() {
+        return treeInfoDao.findRootNodes();
+    }
+
+    /**
+     * 导入知识库数据
+     * @param dataList Excel解析后的数据列表
+     * @param rootId 根节点id
+     * @return 导入结果描述
+     */
+    @Transactional(readOnly = false)
+    public String importData(List<WorkKnowledgeBaseImportInfo> dataList, String rootId) {
+        if (dataList == null || dataList.isEmpty()) {
+            return "导入数据为空!";
+        }
+
+        // 查询该根节点下的动态字段配置,用于将导入字段映射为动态字段id
+        List<WorkKnowledgeBaseDynamicInfo> dynamicFields = dynamicInfoDao.findByRootId(rootId);
+        // 构建 fieldKey -> fieldId 的映射
+        Map<String, String> fieldKeyToIdMap = new HashMap<>();
+        for (WorkKnowledgeBaseDynamicInfo field : dynamicFields) {
+            fieldKeyToIdMap.put(field.getFieldKey(), field.getId());
+        }
+
+        int successCount = 0;
+        int failCount = 0;
+        StringBuilder failureMsg = new StringBuilder();
+
+        for (int i = 0; i < dataList.size(); i++) {
+            WorkKnowledgeBaseImportInfo importInfo = dataList.get(i);
+            try {
+                // 1. 根据体系节点名称查找对应的树节点id
+                String systemNodeName = importInfo.getSystemNodeName();
+                if (StringUtils.isBlank(systemNodeName)) {
+                    failCount++;
+                    failureMsg.append("<br/>第").append(i + 2).append("行:体系节点名称为空,跳过;");
+                    continue;
+                }
+                String treeNodeId = treeInfoDao.findIdByTreeName(systemNodeName.trim());
+                if (StringUtils.isBlank(treeNodeId)) {
+                    failCount++;
+                    failureMsg.append("<br/>第").append(i + 2).append("行:未找到体系节点[").append(systemNodeName).append("],跳过;");
+                    continue;
+                }
+
+                // 2. 标准名称为必填项
+                String standardName = importInfo.getStandardName();
+                if (StringUtils.isBlank(standardName)) {
+                    failCount++;
+                    failureMsg.append("<br/>第").append(i + 2).append("行:标准名称为空,跳过;");
+                    continue;
+                }
+
+                // 3. 新增 work_knowledge_base_share_info 记录
+                WorkKnowledgeBaseShareInfo shareInfo = new WorkKnowledgeBaseShareInfo();
+                shareInfo.setIsNewRecord(true);
+                shareInfo.setId(IdGen.uuid());
+                shareInfo.setTreeNodeId(treeNodeId);
+                shareInfo.setName(standardName.trim());
+                shareInfo.preInsert();
+                dao.insert(shareInfo);
+
+                // 4. 将其余字段作为动态字段值插入
+                insertDynamicValue(shareInfo.getId(), "SerialNumber", importInfo.getStandardSystemCode(), fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "StandardNum", importInfo.getStandardNoOrDocumentNo(), fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "ForwardingNum", importInfo.getTransmitDocumentNo(), fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "IssuingDep", importInfo.getPublishDepartment(), fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "EffectiveDate", importInfo.getEffectiveDate() != null ? new java.text.SimpleDateFormat("yyyy-MM-dd").format(importInfo.getEffectiveDate()) : "", fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "StandardLevel", importInfo.getStandardLevel(), fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "VoltageLevel", importInfo.getVoltageLevel(), fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "ProjectType", importInfo.getProjectType(), fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "PreparationStatus", importInfo.getCompileStatus(), fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "SupersededStandardNum", importInfo.getReplacedStandardNoAndName(), fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "StandardRelationship", importInfo.getStandardRelation(), fieldKeyToIdMap);
+                insertDynamicValue(shareInfo.getId(), "remarks", importInfo.getRemark(), fieldKeyToIdMap);
+
+                successCount++;
+            } catch (Exception e) {
+                failCount++;
+                failureMsg.append("<br/>第").append(i + 2).append("行导入失败:").append(e.getMessage()).append(";");
+            }
+        }
+
+        String resultMsg = "成功导入 " + successCount + " 条记录";
+        if (failCount > 0) {
+            resultMsg += ",失败 " + failCount + " 条:" + failureMsg.toString();
+        }
+        return resultMsg;
+    }
+
+    /**
+     * 插入单个动态字段值
+     */
+    private void insertDynamicValue(String fileId, String fieldKey, String fieldValue, Map<String, String> fieldKeyToIdMap) {
+        String dynamicFieldId = fieldKeyToIdMap.get(fieldKey);
+        if (StringUtils.isBlank(dynamicFieldId) || StringUtils.isBlank(fieldValue)) {
+            return;
+        }
+        WorkKnowledgeBaseDynamicValueInfo valueInfo = new WorkKnowledgeBaseDynamicValueInfo();
+        valueInfo.setId(IdGen.uuid());
+        valueInfo.setFileId(fileId);
+        valueInfo.setDynamicFieldId(dynamicFieldId);
+        valueInfo.setFieldValue(fieldValue.trim());
+        valueInfo.preInsert();
+        dynamicValueInfoDao.insert(valueInfo);
+    }
 }

+ 85 - 11
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseTreeService.java

@@ -8,11 +8,17 @@ import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseDynamicInfoDao
 import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseTreeInfoDao;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo;
+import com.jeeplus.modules.sys.entity.Workattachment;
+import com.jeeplus.modules.sys.service.WorkattachmentService;
+import com.jeeplus.modules.sys.utils.UserUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * 知识库-树形节点 Service
@@ -26,6 +32,12 @@ public class WorkKnowledgeBaseTreeService extends CrudService<WorkKnowledgeBaseT
     @Autowired
     private WorkKnowledgeBaseDynamicInfoDao dynamicInfoDao;
 
+    @Autowired
+    private WorkattachmentService workattachmentService;
+
+    /** 树节点描述附件标识 */
+    private static final String TREE_EXPLAIN_ATTACHMENT_FLAG = "200";
+
     /**
      * 查询所有节点(用于构建左侧树)
      */
@@ -90,23 +102,42 @@ public class WorkKnowledgeBaseTreeService extends CrudService<WorkKnowledgeBaseT
         // 仅根节点维护动态字段
         if (isRoot) {
             String rootId = treeInfo.getId();
-            // 先逻辑删除旧的动态字段
-            WorkKnowledgeBaseDynamicInfo delEntity = new WorkKnowledgeBaseDynamicInfo();
-            delEntity.setRootId(rootId);
-            delEntity.preUpdate();
-            dynamicInfoDao.deleteByRootId(delEntity);
-
-            // 重新插入新的动态字段
             List<WorkKnowledgeBaseDynamicInfo> dynamicFields = treeInfo.getDynamicFields();
+
+            // 查询数据库中现有的动态字段
+            List<WorkKnowledgeBaseDynamicInfo> existingFields = dynamicInfoDao.findByRootId(rootId);
+
+            // 收集本次提交的已有字段id集合,用于判断哪些字段被删除
+            Set<String> submittedIds = new HashSet<>();
+
             if (dynamicFields != null) {
                 for (WorkKnowledgeBaseDynamicInfo field : dynamicFields) {
                     if (StringUtils.isBlank(field.getFieldKey()) && StringUtils.isBlank(field.getFieldLabel())) {
                         continue; // 跳过空行
                     }
-                    field.setId(IdGen.uuid());
-                    field.setRootId(rootId);
-                    field.preInsert();
-                    dynamicInfoDao.insert(field);
+                    if (StringUtils.isNotBlank(field.getId()) && !"null".equals(field.getId())) {
+                        // 已有字段:执行更新
+                        submittedIds.add(field.getId());
+                        field.setRootId(rootId);
+                        field.preUpdate();
+                        dynamicInfoDao.update(field);
+                    } else {
+                        // 新增字段:生成id后插入
+                        field.setId(IdGen.uuid());
+                        field.setRootId(rootId);
+                        field.preInsert();
+                        dynamicInfoDao.insert(field);
+                    }
+                }
+            }
+
+            // 对于数据库中存在但本次提交中未包含的字段,执行逻辑删除
+            if (existingFields != null) {
+                for (WorkKnowledgeBaseDynamicInfo existField : existingFields) {
+                    if (!submittedIds.contains(existField.getId())) {
+                        existField.preUpdate();
+                        dynamicInfoDao.deleteByLogic(existField);
+                    }
                 }
             }
         }
@@ -124,4 +155,47 @@ public class WorkKnowledgeBaseTreeService extends CrudService<WorkKnowledgeBaseT
     public Page<WorkKnowledgeBaseTreeInfo> findPage(Page<WorkKnowledgeBaseTreeInfo> page, WorkKnowledgeBaseTreeInfo entity) {
         return super.findPage(page, entity);
     }
+
+    /**
+     * 保存类型描述(explain + 附件)
+     */
+    @Transactional(readOnly = false)
+    public void saveExplain(WorkKnowledgeBaseTreeInfo treeInfo) {
+        treeInfo.preUpdate();
+        dao.updateExplain(treeInfo);
+
+        // 保存附件
+        List<Workattachment> attachments = treeInfo.getWorkAttachments();
+        if (attachments != null) {
+            for (Workattachment attachment : attachments) {
+                if (attachment.getId() == null) {
+                    continue;
+                }
+                if (Workattachment.DEL_FLAG_NORMAL.equals(attachment.getDelFlag())) {
+                    attachment.setAttachmentId(treeInfo.getId());
+                    attachment.setAttachmentFlag(TREE_EXPLAIN_ATTACHMENT_FLAG);
+                    attachment.setAttachmentUser(UserUtils.getUser().getId());
+                    if (StringUtils.isBlank(attachment.getId()) || "null".equals(attachment.getId())) {
+                        workattachmentService.insertOnWorkAttachment(attachment);
+                    } else {
+                        workattachmentService.updateOnWorkAttachment(attachment);
+                    }
+                } else {
+                    workattachmentService.delete(attachment);
+                }
+            }
+        }
+    }
+
+    /**
+     * 加载树节点描述附件
+     */
+    public List<Workattachment> findExplainAttachments(String treeId) {
+        if (StringUtils.isBlank(treeId)) {
+            return new ArrayList<>();
+        }
+        List<Workattachment> list = workattachmentService.getListByAttachmentIdAndFlag(treeId, TREE_EXPLAIN_ATTACHMENT_FLAG);
+        workattachmentService.workAttachmentManage(list);
+        return list;
+    }
 }

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

@@ -4,9 +4,11 @@ import com.alibaba.fastjson.JSON;
 import com.jeeplus.common.config.Global;
 import com.jeeplus.common.persistence.Page;
 import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.common.utils.excel.ImportExcel;
 import com.jeeplus.common.web.BaseController;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicValueInfo;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseImportInfo;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseShareInfo;
 import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBaseShareService;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -14,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
 import javax.servlet.http.HttpServletRequest;
@@ -241,4 +244,38 @@ public class WorkKnowledgeBaseShareController extends BaseController {
     public List<WorkKnowledgeBaseDynamicInfo> getDynamicFields(@RequestParam String rootId) {
         return shareService.findDynamicFields(rootId);
     }
+
+    /**
+     * 导入弹窗页面
+     */
+    @RequiresPermissions("workKnowledgeBase:share:import")
+    @RequestMapping(value = "importForm")
+    public String importForm(@RequestParam(required = false) String rootId, Model model) {
+        model.addAttribute("rootId", rootId);
+        // 查询所有根节点(parent_id = '0'的节点)用于下拉选择
+        model.addAttribute("rootNodes", shareService.findRootNodes());
+        return "modules/WorkKnowledgeBase/workKnowledgeBaseShareImport";
+    }
+
+    /**
+     * 执行导入
+     */
+    @RequiresPermissions("workKnowledgeBase:share:import")
+    @RequestMapping(value = "importFile", method = RequestMethod.POST)
+    @ResponseBody
+    public Map<String, Object> importFile(@RequestParam MultipartFile file,
+                                          @RequestParam String rootId) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            ImportExcel ei = new ImportExcel(file, 1, 0);
+            List<WorkKnowledgeBaseImportInfo> list = ei.getDataList(WorkKnowledgeBaseImportInfo.class);
+            String resultMsg = shareService.importData(list, rootId);
+            result.put("success", true);
+            result.put("message", resultMsg);
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", "导入失败:" + e.getMessage());
+        }
+        return result;
+    }
 }

+ 51 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseTreeController.java

@@ -5,6 +5,8 @@ import com.jeeplus.common.utils.StringUtils;
 import com.jeeplus.common.web.BaseController;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo;
 import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBaseTreeService;
+import com.jeeplus.modules.sys.entity.Workattachment;
+import org.apache.shiro.authz.annotation.Logical;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
@@ -148,4 +150,53 @@ public class WorkKnowledgeBaseTreeController extends BaseController {
         }
         return result;
     }
+
+    /**
+     * 类型描述编辑表单
+     */
+    @RequiresPermissions(value = {"workKnowledgeBase:tree:add", "workKnowledgeBase:tree:edit"}, logical = Logical.OR)
+    @RequestMapping(value = "explainForm")
+    public String explainForm(@RequestParam String id, Model model) {
+        WorkKnowledgeBaseTreeInfo treeInfo = treeService.get(id);
+        if (treeInfo != null) {
+            List<Workattachment> attachments = treeService.findExplainAttachments(id);
+            treeInfo.setWorkAttachments(attachments);
+        }
+        model.addAttribute("workKnowledgeBaseTreeInfo", treeInfo);
+        return "modules/WorkKnowledgeBase/workKnowledgeBaseTreeExplainForm";
+    }
+
+    /**
+     * 保存类型描述
+     */
+    @RequiresPermissions(value = {"workKnowledgeBase:tree:add", "workKnowledgeBase:tree:edit"}, logical = Logical.OR)
+    @RequestMapping(value = "saveExplain")
+    @ResponseBody
+    public Map<String, Object> saveExplain(WorkKnowledgeBaseTreeInfo treeInfo) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            treeService.saveExplain(treeInfo);
+            result.put("success", true);
+            result.put("message", "保存成功");
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", "保存失败:" + e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 查看类型描述(只读)
+     */
+    @RequiresPermissions(value = {"workKnowledgeBase:tree:list", "workKnowledgeBase:tree:edit"}, logical = Logical.OR)
+    @RequestMapping(value = "explainView")
+    public String explainView(@RequestParam String id, Model model) {
+        WorkKnowledgeBaseTreeInfo treeInfo = treeService.get(id);
+        if (treeInfo != null) {
+            List<Workattachment> attachments = treeService.findExplainAttachments(id);
+            treeInfo.setWorkAttachments(attachments);
+        }
+        model.addAttribute("workKnowledgeBaseTreeInfo", treeInfo);
+        return "modules/WorkKnowledgeBase/workKnowledgeBaseTreeExplainView";
+    }
 }

+ 3 - 0
src/main/java/com/jeeplus/modules/knowledgeSharing/dify/KnowledgeDifyController.java

@@ -66,6 +66,9 @@ public class KnowledgeDifyController extends BaseController {
                 case "10":   //材价库
                     model.addAttribute("difySrc", difySrc + "oseq5jPj6Y4rYCz6");
                     break;
+                case "11":   //国网基建内容
+                    model.addAttribute("difySrc", difySrc + "xVxPYp0WX60u3baP");
+                    break;
                 default:
                     model.addAttribute("difySrc", difySrc + "Yl0XaVnhykBRU2Xl");
                     break;

+ 3 - 4
src/main/java/com/jeeplus/modules/knowledgeSharing/web/KnowledgeBaseController.java

@@ -9,9 +9,7 @@ import com.jeeplus.modules.knowledgeSharing.service.KnowledgeBaseService;
 import com.jeeplus.modules.knowledgeSharing.service.KnowledgeSharingTypeService;
 import com.jeeplus.modules.sys.utils.UserUtils;
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
-import org.apache.shiro.authz.annotation.Logical;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
-import org.json.JSONArray;
 import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
@@ -20,10 +18,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.multipart.MultipartFile;
 
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
 import java.io.InputStream;
 import java.util.*;
 
@@ -109,6 +105,9 @@ public class KnowledgeBaseController {
                 case "10":   //材价库
                     model.addAttribute("difySrc", difySrc + "oseq5jPj6Y4rYCz6");
                     break;
+                case "11":   //国网基建内容
+                    model.addAttribute("difySrc", difySrc + "xVxPYp0WX60u3baP");
+                    break;
                 default:
                     model.addAttribute("difySrc", difySrc + "Yl0XaVnhykBRU2Xl");
                     break;

+ 6 - 0
src/main/java/com/jeeplus/modules/workstaff/dao/WorkStaffCertificateDao.java

@@ -38,6 +38,12 @@ public interface WorkStaffCertificateDao extends CrudDao<WorkStaffCertificate> {
     void updateImport(WorkStaffCertificateImport info);
 
     /**
+     * 修改批量添加职业资格信息
+     * @param info
+     */
+    void updateCertificateValidity(WorkStaffCertificate info);
+
+    /**
      * 查询所有的一级造价师信息
      * @return
      */

+ 71 - 8
src/main/java/com/jeeplus/modules/workstaff/service/WorkStaffCertificateService.java

@@ -953,11 +953,42 @@ public class WorkStaffCertificateService extends CrudService<WorkStaffCertificat
                                 // 转换为 Date
                                 sdf = new SimpleDateFormat("yyyy年MM月dd日");
 
-                                newCertificate.setValidStartDate(sdf.parse(startDateStr));
-                                newCertificate.setValidEndDate(sdf.parse(endDateStr));
-                                newCertificate.setStartDate(sdf.parse(certValidStartDateStr));
-                                newCertificate.setEndDate(sdf.parse(certValidEndDateStr));
+                                //newCertificate.setValidStartDate(sdf.parse(startDateStr));
+                                newCertificate.setValidStartDate(
+                                        startDateStr == null ? new Date() : sdf.parse(startDateStr)
+                                );
+                                //newCertificate.setValidEndDate(sdf.parse(endDateStr));
+
+                                Date endDate;
+                                if (endDateStr == null) {
+                                    Calendar c = Calendar.getInstance();
+                                    c.add(Calendar.MONTH, 3);
+                                    endDate = c.getTime();
+                                } else {
+                                    endDate = sdf.parse(endDateStr);
+                                }
+
+                                newCertificate.setValidEndDate(endDate);
+
+                                //newCertificate.setStartDate(sdf.parse(certValidStartDateStr));
+                                newCertificate.setStartDate(
+                                        certValidStartDateStr == null ? new Date() : sdf.parse(certValidStartDateStr)
+                                );
+
+                                //newCertificate.setEndDate(sdf.parse(certValidEndDateStr));
 
+                                Date certValidEndDate;
+                                if (certValidEndDateStr == null) {
+                                    Calendar c = Calendar.getInstance();
+                                    c.add(Calendar.MONTH, 3);
+                                    certValidEndDate = c.getTime();
+                                } else {
+                                    certValidEndDate = sdf.parse(certValidEndDateStr);
+                                }
+                                newCertificate.setEndDate(certValidEndDate);
+
+                                //修改证书的有效日期
+                                certificateDao.updateCertificateValidity(newCertificate);
                                 // -------------------------- 4. 条件判断:name=161 且 是PDF,调用disposeFile --------------------------
 
                             }else{
@@ -1175,10 +1206,42 @@ public class WorkStaffCertificateService extends CrudService<WorkStaffCertificat
                                 // 转换为 Date
                                 sdf = new SimpleDateFormat("yyyy年MM月dd日");
 
-                                newCertificate.setValidStartDate(sdf.parse(startDateStr));
-                                newCertificate.setValidEndDate(sdf.parse(endDateStr));
-                                newCertificate.setStartDate(sdf.parse(certValidStartDateStr));
-                                newCertificate.setEndDate(sdf.parse(certValidEndDateStr));
+                                //newCertificate.setValidStartDate(sdf.parse(startDateStr));
+                                newCertificate.setValidStartDate(
+                                        startDateStr == null ? new Date() : sdf.parse(startDateStr)
+                                );
+                                //newCertificate.setValidEndDate(sdf.parse(endDateStr));
+
+                                Date endDate;
+                                if (endDateStr == null) {
+                                    Calendar c = Calendar.getInstance();
+                                    c.add(Calendar.MONTH, 3);
+                                    endDate = c.getTime();
+                                } else {
+                                    endDate = sdf.parse(endDateStr);
+                                }
+
+                                newCertificate.setValidEndDate(endDate);
+
+                                //newCertificate.setStartDate(sdf.parse(certValidStartDateStr));
+                                newCertificate.setStartDate(
+                                        certValidStartDateStr == null ? new Date() : sdf.parse(certValidStartDateStr)
+                                );
+
+                                //newCertificate.setEndDate(sdf.parse(certValidEndDateStr));
+
+                                Date certValidEndDate;
+                                if (certValidEndDateStr == null) {
+                                    Calendar c = Calendar.getInstance();
+                                    c.add(Calendar.MONTH, 3);
+                                    certValidEndDate = c.getTime();
+                                } else {
+                                    certValidEndDate = sdf.parse(certValidEndDateStr);
+                                }
+                                newCertificate.setEndDate(certValidEndDate);
+
+                                //修改证书的有效日期
+                                certificateDao.updateCertificateValidity(newCertificate);
 
                                 // -------------------------- 4. 条件判断:name=161 且 是PDF,调用disposeFile --------------------------
 

+ 1 - 0
src/main/java/com/jeeplus/modules/workstaff/utils/PdfSignUtil.java

@@ -185,6 +185,7 @@ public class PdfSignUtil {
 
         } catch (Exception e) {
             e.printStackTrace();
+            System.out.println("✅ 文件处理失败,失败原因:" + e.getMessage());
         } finally {
             try { if (doc != null) doc.close(); } catch (Exception ignored) {}
         }

+ 4 - 3
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseShareInfoDao.xml

@@ -68,7 +68,8 @@
             a.create_by                                           AS "createById",
             (SELECT su.name FROM sys_user su WHERE su.id = a.create_by) AS "createByName",
             a.create_date                                         AS "createDate",
-            a.remarks                                             AS "remarks"
+            a.remarks                                             AS "remarks",
+            su.name                                               AS "createBy.name"
             <!-- 动态列:CASE WHEN + MAX + GROUP BY -->
             <if test="dynamicFields != null and dynamicFields.size() > 0">
                 <foreach collection="dynamicFields" item="field" separator="">
@@ -76,8 +77,8 @@
                 </foreach>
             </if>
         FROM work_knowledge_base_share_info a
-        LEFT JOIN work_knowledge_base_dynamic_value_info v
-            ON v.file_id = a.id AND v.del_flag = '0'
+        LEFT JOIN work_knowledge_base_dynamic_value_info v ON v.file_id = a.id AND v.del_flag = '0'
+        LEFT JOIN sys_user su ON su.id = a.create_by AND su.del_flag = '0'
         <where>
             a.del_flag = '0'
             <!-- 匹配当前选中节点及其所有子节点的数据 -->

+ 47 - 5
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseTreeInfoDao.xml

@@ -9,6 +9,7 @@
         a.root_id      AS "rootId",
         a.tree_name    AS "treeName",
         a.sort         AS "sort",
+        a.`explain`      AS "explain",
         a.create_by    AS "createBy.id",
         a.create_date  AS "createDate",
         a.update_by    AS "updateBy.id",
@@ -37,9 +38,22 @@
         ORDER BY a.sort ASC, a.create_date DESC
     </select>
 
-    <!-- 查询全部树节点(用于左侧树构建) -->
+    <!-- 查询全部树节点(用于左侧树构建,explain只返回是否有值标识) -->
     <select id="findAllTreeList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo">
-        SELECT <include refid="treeColumns"/>
+        SELECT
+            a.id           AS "id",
+            a.parent_id    AS "parentId",
+            a.parent_ids   AS "parentIds",
+            a.root_id      AS "rootId",
+            a.tree_name    AS "treeName",
+            a.sort         AS "sort",
+            CASE WHEN a.`explain` IS NOT NULL AND a.`explain` != '' THEN '1' ELSE '' END AS "explain",
+            a.create_by    AS "createBy.id",
+            a.create_date  AS "createDate",
+            a.update_by    AS "updateBy.id",
+            a.update_date  AS "updateDate",
+            a.remarks      AS "remarks",
+            a.del_flag     AS "delFlag"
         FROM work_knowledge_base_tree_info a
         WHERE a.del_flag = #{DEL_FLAG_NORMAL}
         ORDER BY a.sort ASC, a.create_date ASC
@@ -84,10 +98,10 @@
     <!-- 插入 -->
     <insert id="insert">
         INSERT INTO work_knowledge_base_tree_info (
-            id, parent_id, parent_ids, root_id, tree_name, sort,
+            id, parent_id, parent_ids, root_id, tree_name, sort, `explain`,
             create_by, create_date, update_by, update_date, remarks, del_flag
         ) VALUES (
-            #{id}, #{parentId}, #{parentIds}, #{rootId}, #{treeName}, #{sort},
+            #{id}, #{parentId}, #{parentIds}, #{rootId}, #{treeName}, #{sort}, #{explain},
             #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks}, #{delFlag}
         )
     </insert>
@@ -97,6 +111,7 @@
         UPDATE work_knowledge_base_tree_info SET
             tree_name   = #{treeName},
             sort        = #{sort},
+            `explain`     = #{explain},
             update_by   = #{updateBy.id},
             update_date = #{updateDate},
             remarks     = #{remarks}
@@ -117,7 +132,7 @@
         WHERE id = #{id}
     </update>
 
-    <!-- 逻辑删除(含所有子节点,通过 parent_ids LIKE) -->
+    <!-- 逻辑删除(含所有子节点,通过 parent_ids LIKE) -->
     <update id="deleteByLogicWithChildren">
         UPDATE work_knowledge_base_tree_info SET
             del_flag    = '1',
@@ -127,4 +142,31 @@
            OR parent_ids LIKE CONCAT('%,', #{id}, ',%')
     </update>
 
+    <!-- 单独更新 explain 字段 -->
+    <update id="updateExplain">
+        UPDATE work_knowledge_base_tree_info SET
+            `explain`     = #{explain},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 根据节点名称精确查找节点id -->
+    <select id="findIdByTreeName" resultType="java.lang.String">
+        SELECT id
+        FROM work_knowledge_base_tree_info
+        WHERE tree_name = #{treeName}
+          AND del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <!-- 查询所有根节点(parent_id='0'的节点) -->
+    <select id="findRootNodes" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo">
+        SELECT <include refid="treeColumns"/>
+        FROM work_knowledge_base_tree_info a
+        WHERE a.parent_id = '0'
+          AND a.del_flag = '0'
+        ORDER BY a.sort ASC
+    </select>
+
 </mapper>

+ 15 - 0
src/main/resources/mappings/modules/workstaff/WorkStaffCertificateDao.xml

@@ -166,6 +166,21 @@
 			end_date = #{endDate}
 		WHERE id = #{id}
 	</update>
+
+	<update id="updateCertificateValidity">
+		UPDATE work_staff_certificate SET
+			<if test="validStartDate !=null">
+				valid_start_date = #{validStartDate},
+			</if>
+			<if test="validEndDate !=null">
+				valid_end_date = #{validEndDate},
+			</if>
+			<if test="startDate !=null">
+				start_date = #{startDate},
+			</if>
+			end_date = #{endDate}
+		WHERE id = #{id}
+	</update>
 	
 	
 	<!--物理删除-->

+ 67 - 4
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseIndex.jsp

@@ -57,6 +57,51 @@
             openTreeDialog('编辑节点', '${ctx}/workKnowledgeBase/tree/form?id=' + nodeId, '1000px', '800px', true);
         }
 
+        /** 添加/编辑类型描述 */
+        function openExplainForm(nodeId) {
+            top.layer.open({
+                type: 2,
+                area: ['80%', '80%'],
+                title: '添加类型描述',
+                maxmin: true,
+                content: '${ctx}/workKnowledgeBase/tree/explainForm?id=' + nodeId,
+                btn: ['提交', '关闭'],
+                btn1: function(index, layero) {
+                    var body = top.layer.getChildFrame('body', index);
+                    var iframeWin = layero.find('iframe')[0];
+                    if (iframeWin.contentWindow.doSubmit(1)) {
+                        setTimeout(function() {
+                            top.layer.close(index);
+                            // 刷新树并保持当前选中节点
+                            var savedNodeId = currentNodeId;
+                            var savedRootId = currentRootId;
+                            refreshTree(function() {
+                                selectNodeById(savedNodeId, savedRootId);
+                            });
+                        }, 300);
+                    }
+                },
+                btn2: function(index) {
+                    top.layer.close(index);
+                }
+            });
+        }
+
+        /** 查看类型描述 */
+        function openExplainView(nodeId) {
+            top.layer.open({
+                type: 2,
+                area: ['80%', '80%'],
+                title: '查看类型描述',
+                maxmin: true,
+                content: '${ctx}/workKnowledgeBase/tree/explainView?id=' + nodeId,
+                btn: ['关闭'],
+                btn1: function(index) {
+                    top.layer.close(index);
+                }
+            });
+        }
+
         /** 删除节点 */
         function deleteNode(nodeId) {
             layer.open({
@@ -169,6 +214,11 @@
             $('#treeContainer').html(html);
         }
 
+        // 权限控制变量(JSP 服务端渲染)
+        var permTreeAdd = <shiro:hasPermission name="workKnowledgeBase:tree:add">true</shiro:hasPermission><shiro:lacksPermission name="workKnowledgeBase:tree:add">false</shiro:lacksPermission>;
+        var permTreeEdit = <shiro:hasPermission name="workKnowledgeBase:tree:edit">true</shiro:hasPermission><shiro:lacksPermission name="workKnowledgeBase:tree:edit">false</shiro:lacksPermission>;
+        var permTreeDel = <shiro:hasPermission name="workKnowledgeBase:tree:del">true</shiro:hasPermission><shiro:lacksPermission name="workKnowledgeBase:tree:del">false</shiro:lacksPermission>;
+
         /** 递归构建树HTML */
         function buildTreeHtml(nodes, parentId, depth) {
             depth = depth || 0;
@@ -189,9 +239,22 @@
                     }
                     html += '<span class="tree-name" title="' + node.treeName + '">' + node.treeName + '</span>';
                     html += '<span class="tree-ops pull-right">';
-                    html += '<a href="javascript:void(0)" onclick="addChildNode(\'' + node.id + '\')" title="新增子节点"><i class="glyphicon glyphicon-plus"></i></a>&nbsp;';
-                    html += '<a href="javascript:void(0)" onclick="editNode(\'' + node.id + '\')" title="编辑"><i class="glyphicon glyphicon-pencil"></i></a>&nbsp;';
-                    html += '<a href="javascript:void(0)" onclick="deleteNode(\'' + node.id + '\')" title="删除"><i class="glyphicon glyphicon-trash"></i></a>';
+
+                    if (permTreeAdd) {
+                        html += '<a href="javascript:void(0)" onclick="addChildNode(\'' + node.id + '\')" title="新增子节点"><i class="glyphicon glyphicon-plus"></i></a>&nbsp;';
+                    }
+                    if (permTreeEdit) {
+                        html += '<a href="javascript:void(0)" onclick="openExplainForm(\'' + node.id + '\')" title="添加类型描述"><i class="glyphicon glyphicon-edit"></i></a>&nbsp;';
+                    }
+                    if (node.explain && node.explain !== '') {
+                        html += '<a href="javascript:void(0)" onclick="openExplainView(\'' + node.id + '\')" title="查看描述"><i class="glyphicon glyphicon-eye-open"></i></a>&nbsp;';
+                    }
+                    if (permTreeEdit) {
+                        html += '<a href="javascript:void(0)" onclick="editNode(\'' + node.id + '\')" title="编辑"><i class="glyphicon glyphicon-pencil"></i></a>&nbsp;';
+                    }
+                    if (permTreeDel) {
+                        html += '<a href="javascript:void(0)" onclick="deleteNode(\'' + node.id + '\')" title="删除"><i class="glyphicon glyphicon-trash"></i></a>';
+                    }
                     html += '</span>';
                     html += '</div>';
                     if (hasChildren) {
@@ -241,7 +304,7 @@
         body { background-color: transparent; }
         .kb-layout { display: flex; width: 100%; min-height: calc(100vh - 60px); }
         .kb-left {
-            width: 240px;
+            width: 280px;
             min-width: 200px;
             background: #fff;
             border-right: 1px solid #e5e5e5;

+ 2 - 2
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareDetail.jsp

@@ -59,12 +59,12 @@
         </c:if>
 
         <!-- 备注 -->
-        <div class="layui-item layui-col-sm12 lw6">
+        <%--<div class="layui-item layui-col-sm12 lw6">
             <label class="layui-form-label detail-label">备注:</label>
             <div class="layui-input-block">
                 <textarea class="layui-textarea" readonly="readonly" rows="4">${entity.remarks}</textarea>
             </div>
-        </div>
+        </div>--%>
 
         <!-- 附件展示 -->
         <c:if test="${not empty entity.workAttachments}">

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

@@ -180,12 +180,12 @@
 
 
             <!-- 备注 -->
-            <div class="layui-form-item layui-col-sm12 lw6">
+            <%--<div class="layui-form-item layui-col-sm12 lw6">
                 <label class="layui-form-label">备注:</label>
                 <div class="layui-input-block">
                     <form:textarea path="remarks" placeholder="备注信息" rows="4" maxlength="200" class="layui-textarea"></form:textarea>
                 </div>
-            </div>
+            </div>--%>
 
 
 

+ 94 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareImport.jsp

@@ -0,0 +1,94 @@
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@ include file="/webpage/include/taglib.jsp"%>
+<html>
+<head>
+    <title>导入知识库数据</title>
+    <meta name="decorator" content="default"/>
+    <script type="text/javascript" src="${ctxStatic}/layui/layui.js"></script>
+    <link rel='stylesheet' type="text/css" href="${ctxStatic}/layui/css/layui.css"/>
+    <script type="text/javascript">
+        function doSubmit(i) {
+            var fileInput = document.getElementById('importFile');
+            if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
+                parent.layer.msg('请选择要导入的文件!', {icon: 5});
+                return false;
+            }
+            var rootId = $('#rootId').val();
+            if (!rootId) {
+                parent.layer.msg('请选择根节点!', {icon: 5});
+                return false;
+            }
+
+            // 使用Ajax提交表单
+            var formData = new FormData();
+            formData.append('file', fileInput.files[0]);
+            formData.append('rootId', rootId);
+
+            loading('正在导入,请稍等...');
+            $.ajax({
+                url: '${ctx}/workKnowledgeBase/share/importFile',
+                type: 'POST',
+                data: formData,
+                processData: false,
+                contentType: false,
+                success: function(data) {
+                    closeLoading();
+                    if (data.success) {
+                        parent.layer.msg(data.message, {icon: 1, time: 3000});
+                    } else {
+                        parent.layer.msg(data.message, {icon: 2, time: 5000});
+                    }
+                },
+                error: function() {
+                    closeLoading();
+                    parent.layer.msg('导入请求异常!', {icon: 2});
+                }
+            });
+            return true;
+        }
+
+        $(document).ready(function() {
+            layui.use(['form'], function() {
+                var form = layui.form;
+                form.render();
+            });
+        });
+    </script>
+</head>
+<body>
+<div class="single-form">
+    <div class="container">
+        <form id="inputForm" enctype="multipart/form-data" class="form-horizontal layui-form">
+            <sys:message content="${message}"/>
+            <div class="form-group layui-row first">
+                <div class="form-group-label"><h2>导入知识库数据</h2></div>
+
+                <div class="layui-item layui-col-sm12 lw6">
+                    <label class="layui-form-label"><span class="require-item">*</span>根节点:</label>
+                    <div class="layui-input-block">
+                        <select id="rootId" name="rootId" lay-verify="required" class="form-control judgment">
+                            <option value="">请选择根节点</option>
+                            <c:forEach items="${rootNodes}" var="node">
+                                <option value="${node.id}" <c:if test="${node.id == rootId}">selected</c:if>>${node.treeName}</option>
+                            </c:forEach>
+                        </select>
+                    </div>
+                </div>
+
+                <div class="layui-item layui-col-sm12 lw6">
+                    <label class="layui-form-label"><span class="require-item">*</span>导入文件:</label>
+                    <div class="layui-input-block">
+                        <input id="importFile" name="file" type="file" accept=".xls,.xlsx"
+                               class="form-control layui-input" style="padding: 5px;"/>
+                        <p class="help-block" style="color: #999; margin-top: 5px;">
+                            支持 .xls 和 .xlsx 格式文件,数据从第2行开始读取(第1行为标题行)
+                        </p>
+                    </div>
+                </div>
+            </div>
+            <div class="form-group layui-row page-end"></div>
+        </form>
+    </div>
+</div>
+</body>
+</html>

+ 36 - 3
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareList.jsp

@@ -116,6 +116,29 @@
             $('#searchForm').submit();
         }
 
+        /** 导入弹窗 */
+        function openImportDialog() {
+            top.layer.open({
+                type: 2,
+                area: ['500px', '400px'],
+                title: '导入知识库数据',
+                maxmin: false,
+                content: '${ctx}/workKnowledgeBase/share/importForm?rootId=${rootId}',
+                skin: 'three-btns',
+                btn: ['开始导入', '关闭'],
+                btn1: function(index, layero) {
+                    var iframeWin = layero.find('iframe')[0];
+                    if (iframeWin.contentWindow.doSubmit(1)) {
+                        setTimeout(function() {
+                            top.layer.close(index);
+                            search();
+                        }, 2000);
+                    }
+                },
+                btn2: function(index) { top.layer.close(index); }
+            });
+        }
+
         /** 重置查询 */
         function resetSearch() {
             $('#searchForm input[type=text]').val('');
@@ -168,7 +191,7 @@
                         </div>
                         <div class="layui-item athird">
                             <div class="input-group">
-                                <%--<a href="#" id="moresee"><i class="glyphicon glyphicon-menu-down"></i></a>--%>
+                                <a href="#" id="moresee"><i class="glyphicon glyphicon-menu-down"></i></a>
                                 <div class="layui-btn-group search-spacing">
                                     <button id="searchQuery" class="layui-btn layui-btn-sm layui-bg-blue" onclick="search()">查询</button>
                                     <button id="searchReset" class="layui-btn layui-btn-sm" onclick="resetSearch()">重置</button>
@@ -216,6 +239,12 @@
                                     <i class="glyphicon glyphicon-plus"></i> 新增
                                 </button>
                             </shiro:hasPermission>
+                            <shiro:hasPermission name="workKnowledgeBase:share:import">
+                                <button class="layui-btn layui-btn-sm layui-bg-green"
+                                        onclick="openImportDialog()">
+                                     导入
+                                </button>
+                            </shiro:hasPermission>
                         </c:if>
                         <button class="layui-btn layui-btn-sm" onclick="search()" title="刷新">刷新</button>
                     </div>
@@ -250,7 +279,7 @@
         // 构建动态列配置
         var cols = [
             {field: 'index', align: 'center', width: 50, title: '序号'},
-            {field: 'name', align: 'center', title: '文件名称', minWidth: 150, templet: function(d) {
+            {field: 'name', align: 'center', title: '文件名称', minWidth: 200, templet: function(d) {
                 return '<a href="javascript:void(0)" class="attention-info" onclick="openDetailDialog(\'' + d.id + '\')">' + (d.name || '') + '</a>';
             }},
             {field: 'fileUrl', align: 'center', title: '文件地址', minWidth: 200, templet: function(d) {
@@ -275,6 +304,7 @@
             <c:forEach items="${dynamicFields}" var="field">
             {field: 'dynamic_${field.fieldKey}', align: 'center', title: '${field.fieldLabel}', minWidth: 100},
             </c:forEach>
+            {field: 'createByName', align: 'center', title: '创建人', width: 100},
             {field: 'createTime', align: 'center', title: '创建时间', width: 160},
             {align: 'center', title: '操作', width: 160, fixed: 'right', templet: function(d) {
                 var xml = '<div class="layui-btn-group">';
@@ -310,10 +340,13 @@
                     ,"uploadMode": "<c:out value='${row.uploadMode}'/>"
                     ,"fileUrl": "<c:out value='${row.fileUrl}'/>"
                     ,"createTime": "${row.createTime}"
+                    ,"createByName": "${row.createBy.name}"
+                    ,"userid": "${fns:getUser().id}"
+                    ,"createbyid": "${row.createById}"
                     <c:forEach items="${dynamicFields}" var="field">
                     ,"dynamic_${field.fieldKey}": "<c:out value='${row["dynamic_".concat(field.fieldKey)]}'/>"
 
-                    <c:if test="${fns:getUser().id == row.createBy.id}">
+                    <c:if test="${fns:getUser().id == row.createById}">
                     <shiro:hasPermission name="workKnowledgeBase:share:edit">,"canedit":"1"</shiro:hasPermission>
                     <shiro:hasPermission name="workKnowledgeBase:share:del">,"candelete":"1"</shiro:hasPermission>
                     </c:if>

+ 90 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseTreeExplainForm.jsp

@@ -0,0 +1,90 @@
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@ include file="/webpage/include/taglib.jsp"%>
+<html>
+<head>
+    <title>类型描述</title>
+    <meta name="decorator" content="default"/>
+    <script type="text/javascript" src="${ctxStatic}/layui/layui.js"></script>
+    <link rel='stylesheet' type="text/css" href="${ctxStatic}/layui/css/layui.css"/>
+    <script type="text/javascript">
+        var validateForm;
+        function doSubmit(i){
+            if(validateForm.form()){
+                // 校验富文本描述是否有有效内容
+                var content = CKEDITOR.instances.explain.document.getBody().getText();
+                while (content.indexOf("img{max-width:100%!important;") != -1){
+                    content = content.replace("img{max-width:100%!important;}","");
+                }
+                if(content == null || content == undefined || content.trim() == "" || content.trim() == "\n"){
+                    parent.layer.msg('描述内容不能为空',{icon:5});
+                    return false;
+                }
+                $("#inputForm").submit();
+                return true;
+            }else {
+                parent.layer.msg("信息未填写完整!", {icon: 5});
+            }
+            return false;
+        }
+        $(document).ready(function() {
+            layui.use(['form', 'layer'], function () {
+                var form = layui.form;
+            });
+            validateForm = $("#inputForm").validate({
+                submitHandler: function(form){
+                    loading('正在提交,请稍等...');
+                    form.submit();
+                },
+                errorContainer: "#messageBox",
+                errorPlacement: function(error, element) {
+                    $("#messageBox").text("输入有误,请先更正。");
+                    if (element.is(":checkbox")||element.is(":radio")||element.parent().is(".input-append")){
+                        error.appendTo(element.parent().parent());
+                    } else {
+                        error.insertAfter(element);
+                    }
+                }
+            });
+        });
+    </script>
+</head>
+<body>
+<div class="single-form">
+    <div class="container">
+        <form:form id="inputForm" modelAttribute="workKnowledgeBaseTreeInfo" enctype="multipart/form-data"
+                   action="${ctx}/workKnowledgeBase/tree/saveExplain" method="post" class="form-horizontal layui-form">
+            <form:hidden path="id"/>
+            <sys:message content="${message}"/>
+            <div class="form-group layui-row first">
+                <div class="form-group-label"><h2>类型描述信息</h2></div>
+                <div class="layui-item layui-col-sm12 lw6">
+                    <label class="layui-form-label">节点名称:</label>
+                    <div class="layui-input-block">
+                        <form:input path="treeName" htmlEscape="false" readonly="true" class="form-control layui-input"/>
+                    </div>
+                </div>
+                <div class="layui-item layui-col-sm12" style="padding-bottom: 20px;">
+                    <label class="layui-form-label"><span class="require-item">*</span>描述:</label>
+                    <div class="layui-input-block">
+                        <form:textarea path="explain" htmlEscape="false" colspan="3" rows="6" maxlength="65535" class="form-control judgment"/>
+                        <sys:ckeditor replace="explain" uploadPath="/workKnowledgeBase/tree"/>
+                    </div>
+                </div>
+            </div>
+
+            <table:attachmentManager
+                    title="附件信息"
+                    addBtnText="添加附件"
+                    baseId="attachment"
+                    attachments="${workKnowledgeBaseTreeInfo.workAttachments}"
+                    fileHandlerFuncName="insertTitle"
+                    attachmentFlag="200"
+                    storeAs="workKnowledgeBaseTree"
+            />
+
+            <div class="form-group layui-row page-end"></div>
+        </form:form>
+    </div>
+</div>
+</body>
+</html>

+ 59 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseTreeExplainView.jsp

@@ -0,0 +1,59 @@
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@ include file="/webpage/include/taglib.jsp"%>
+<html>
+<head>
+    <title>查看类型描述</title>
+    <meta name="decorator" content="default"/>
+    <script type="text/javascript" src="${ctxStatic}/layui/layui.js"></script>
+    <link rel='stylesheet' type="text/css" href="${ctxStatic}/layui/css/layui.css"/>
+</head>
+<body>
+<div class="single-form">
+    <div class="container view-form">
+        <div class="form-group layui-row first">
+            <div class="form-group-label"><h2>类型描述信息</h2></div>
+            <div class="layui-item layui-col-sm12 lw6">
+                <label class="layui-form-label">节点名称:</label>
+                <div class="layui-input-block">
+                    <input type="text" value="${workKnowledgeBaseTreeInfo.treeName}" readonly="readonly" class="form-control layui-input"/>
+                </div>
+            </div>
+            <div class="layui-item layui-col-sm12" style="padding-bottom: 20px;">
+                <label class="layui-form-label">描述:</label>
+                <div class="layui-input-block">
+                    <div class="wrapForm">
+                        <div class="mask">
+                            <textarea id="explainContent" name="explain" disabled="disabled" colspan="3" rows="6" class="form-control">${workKnowledgeBaseTreeInfo.explain}</textarea>
+                            <sys:ckeditorView replace="explainContent" uploadPath="/workKnowledgeBase/tree"/>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+
+
+        </div>
+
+        <!-- 附件展示 -->
+        <c:if test="${not empty workKnowledgeBaseTreeInfo.workAttachments}">
+            <!-- fileHandlerFuncName="myCustomHandler" 自定义函数名 -->
+            <!-- attachmentFlag="6" 附件标识 -->
+            <!-- storeAs="wrkReimbursement" 存储路径标识 -->
+            <!-- showOperateArea="false" 是否展示新增按钮,默认true -->
+            <table:attachmentManager
+                    title="附件信息"
+                    addBtnText="添加附件"
+                    baseId="attachment"
+                    attachments="${workKnowledgeBaseTreeInfo.workAttachments}"
+                    fileHandlerFuncName="insertTitle"
+                    attachmentFlag="200"
+                    storeAs="workKnowledgeBaseTree"
+                    showOperateArea="false"
+            />
+        </c:if>
+
+        <div class="form-group layui-row page-end"></div>
+    </div>
+</div>
+</body>
+</html>

+ 1 - 1
src/main/webapp/webpage/modules/workstaff/workStaffBasicCertificateModify.jsp

@@ -352,7 +352,7 @@
             $('#'+spanId).html(imgStr);
         }
         function changelaborContractFileName(obj, index) {
-            console.log("进入changelaborContractFileName方法")
+            console.log("进入changelaborContractFileName方法222")
             // 1. 获取元素的id属性
             const elementId = obj.id;
 

+ 1 - 1
src/main/webapp/webpage/modules/workstaff/workStaffBasicDetailModify.jsp

@@ -620,7 +620,7 @@
         }
 
         function changelaborContractFileName(obj, index) {
-            console.log("进入changelaborContractFileName方法")
+            console.log("进入changelaborContractFileName方法111")
             // 1. 获取元素的id属性
             const elementId = obj.id;