Browse Source

知识库功能未完成版

徐滕 3 weeks atrás
parent
commit
ca428259e7
46 changed files with 5561 additions and 35 deletions
  1. 26 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseDynamicInfoDao.java
  2. 26 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseDynamicValueInfoDao.java
  3. 34 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseShareInfoDao.java
  4. 31 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseTreeInfoDao.java
  5. 68 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseDynamicInfo.java
  6. 50 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseDynamicValueInfo.java
  7. 119 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseShareInfo.java
  8. 92 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseTreeInfo.java
  9. 200 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseShareService.java
  10. 128 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseTreeService.java
  11. 199 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseShareController.java
  12. 149 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseTreeController.java
  13. 2886 0
      src/main/java/com/jeeplus/modules/projectPerformanceDatabase/entity/RuralProjectRecordsPerformance.java
  14. 27 3
      src/main/java/com/jeeplus/modules/projectPerformanceDatabase/web/ProjectPerformanceController.java
  15. 23 9
      src/main/java/com/jeeplus/modules/workcontractinfo/service/WorkContractInfoTookDisposeService.java
  16. 2 1
      src/main/java/com/jeeplus/modules/workcontractinfo/web/WorkContractInfoController.java
  17. 1 1
      src/main/java/com/jeeplus/modules/workinvoice/service/WorkInvoiceService.java
  18. 118 0
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseDynamicInfoDao.xml
  19. 116 0
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseDynamicValueInfoDao.xml
  20. 214 0
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseShareInfoDao.xml
  21. 130 0
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseTreeInfoDao.xml
  22. 8 0
      src/main/resources/mappings/modules/projectPerformanceDatabase/ProjectPerformanceDao.xml
  23. 1 1
      src/main/resources/mappings/modules/projectPerformanceDatabase/ProjectPerformanceDatabaseDao.xml
  24. 3 0
      src/main/resources/mappings/modules/workcontractinfo/WorkContractInfoDao.xml
  25. 1 1
      src/main/webapp/static/common/css/style.css
  26. 1 0
      src/main/webapp/static/common/jeeplus.js
  27. 1 1
      src/main/webapp/webpage/include/head.jsp
  28. 270 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseIndex.jsp
  29. 154 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareForm.jsp
  30. 242 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareList.jsp
  31. 214 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseTreeForm.jsp
  32. 4 1
      src/main/webapp/webpage/modules/projectPerformanceDatabase/projectPerformanceList.jsp
  33. 1 1
      src/main/webapp/webpage/modules/sys/sysLogin.jsp
  34. 1 1
      src/main/webapp/webpage/modules/sys/sysLogin2.jsp
  35. 1 1
      src/main/webapp/webpage/modules/workcontractinfo/newWorkContract/workContractInfoFormAdd.jsp
  36. 10 4
      src/main/webapp/webpage/modules/workcontractinfo/workContractInfoList.jsp
  37. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceAllForm.jsp
  38. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceAllModify.jsp
  39. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceAllRcForm.jsp
  40. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceAllTwoForm.jsp
  41. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceAllTwoRcForm.jsp
  42. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceModify.jsp
  43. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceNotProjectModify.jsp
  44. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceTwoForm.jsp
  45. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceTwoModify.jsp
  46. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceView.jsp

+ 26 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseDynamicInfoDao.java

@@ -0,0 +1,26 @@
+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.WorkKnowledgeBaseDynamicInfo;
+
+import java.util.List;
+
+/**
+ * 知识库-动态字段配置表 DAO
+ * @author: auto
+ * @version: 2026-04-22
+ */
+@MyBatisDao
+public interface WorkKnowledgeBaseDynamicInfoDao extends CrudDao<WorkKnowledgeBaseDynamicInfo> {
+
+    /**
+     * 根据根节点id查询动态字段列表
+     */
+    List<WorkKnowledgeBaseDynamicInfo> findByRootId(String rootId);
+
+    /**
+     * 根据根节点id逻辑删除所有动态字段
+     */
+    void deleteByRootId(WorkKnowledgeBaseDynamicInfo entity);
+}

+ 26 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseDynamicValueInfoDao.java

@@ -0,0 +1,26 @@
+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.WorkKnowledgeBaseDynamicValueInfo;
+
+import java.util.List;
+
+/**
+ * 知识库-动态字段値表 DAO
+ * @author: auto
+ * @version: 2026-04-22
+ */
+@MyBatisDao
+public interface WorkKnowledgeBaseDynamicValueInfoDao extends CrudDao<WorkKnowledgeBaseDynamicValueInfo> {
+
+    /**
+     * 根据文件id逻辑删除所有动态字段値
+     */
+    void deleteByFileId(WorkKnowledgeBaseDynamicValueInfo entity);
+
+    /**
+     * 根据文件id查询所有动态字段値
+     */
+    List<WorkKnowledgeBaseDynamicValueInfo> findByFileId(String fileId);
+}

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

@@ -0,0 +1,34 @@
+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.WorkKnowledgeBaseShareInfo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 知识库-文件信息表 DAO
+ * @author: auto
+ * @version: 2026-04-22
+ */
+@MyBatisDao
+public interface WorkKnowledgeBaseShareInfoDao extends CrudDao<WorkKnowledgeBaseShareInfo> {
+
+    /**
+     * 动态列表查询(含 CASE WHEN 行转列 + EXISTS 动态条件)
+     * @param params 包含 entity(查询实体)、dynamicFields(动态字段列表)、dynamicConditions(动态查询条件Map)
+     */
+    List<Map<String, Object>> findDynamicList(Map<String, Object> params);
+
+    /**
+     * 动态列表查询总数
+     */
+    Integer findDynamicCount(Map<String, Object> params);
+
+    /**
+     * 根据节点id查询数据(用于删除校验等)
+     */
+    List<WorkKnowledgeBaseShareInfo> findByTreeNodeId(String treeNodeId);
+}

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

@@ -0,0 +1,31 @@
+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 java.util.List;
+
+/**
+ * 知识库-树形节点表 DAO
+ * @author: auto
+ * @version: 2026-04-22
+ */
+@MyBatisDao
+public interface WorkKnowledgeBaseTreeInfoDao extends CrudDao<WorkKnowledgeBaseTreeInfo> {
+
+    /**
+     * 查询所有树形节点(用于构建左侧树)
+     */
+    List<WorkKnowledgeBaseTreeInfo> findAllTreeList(WorkKnowledgeBaseTreeInfo entity);
+
+    /**
+     * 根据节点id查询其根节点id
+     */
+    String getRootIdByNodeId(String nodeId);
+
+    /**
+     * 逻辑删除(含子节点)
+     */
+    void deleteByLogicWithChildren(WorkKnowledgeBaseTreeInfo entity);
+}

+ 68 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseDynamicInfo.java

@@ -0,0 +1,68 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+
+/**
+ * 知识库-动态字段配置表实体
+ * @author: auto
+ * @version: 2026-04-22
+ */
+public class WorkKnowledgeBaseDynamicInfo extends DataEntity<WorkKnowledgeBaseDynamicInfo> {
+
+    private String rootId;       // 所属根节点id
+    private String fieldKey;     // 字段标识(英文)
+    private String fieldLabel;   // 字段名称(中文)
+    private String fieldType;    // 字段类型 String/Integer/Double
+    private Integer sort;        // 排序
+
+    /** 动态查询值(用于列表查询时传递的条件值) */
+    private String queryValue;
+
+    public String getRootId() {
+        return rootId;
+    }
+
+    public void setRootId(String rootId) {
+        this.rootId = rootId;
+    }
+
+    public String getFieldKey() {
+        return fieldKey;
+    }
+
+    public void setFieldKey(String fieldKey) {
+        this.fieldKey = fieldKey;
+    }
+
+    public String getFieldLabel() {
+        return fieldLabel;
+    }
+
+    public void setFieldLabel(String fieldLabel) {
+        this.fieldLabel = fieldLabel;
+    }
+
+    public String getFieldType() {
+        return fieldType;
+    }
+
+    public void setFieldType(String fieldType) {
+        this.fieldType = fieldType;
+    }
+
+    public Integer getSort() {
+        return sort;
+    }
+
+    public void setSort(Integer sort) {
+        this.sort = sort;
+    }
+
+    public String getQueryValue() {
+        return queryValue;
+    }
+
+    public void setQueryValue(String queryValue) {
+        this.queryValue = queryValue;
+    }
+}

+ 50 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseDynamicValueInfo.java

@@ -0,0 +1,50 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+
+/**
+ * 知识库-动态字段值表实体
+ * @author: auto
+ * @version: 2026-04-22
+ */
+public class WorkKnowledgeBaseDynamicValueInfo extends DataEntity<WorkKnowledgeBaseDynamicValueInfo> {
+
+    private String fileId;           // 文件id
+    private String dynamicFieldId;   // 动态字段id
+    private String fieldValue;       // 字段值
+
+    /** 字段key(非数据库字段,用于前端交互) */
+    private String fieldKey;
+
+    public String getFileId() {
+        return fileId;
+    }
+
+    public void setFileId(String fileId) {
+        this.fileId = fileId;
+    }
+
+    public String getDynamicFieldId() {
+        return dynamicFieldId;
+    }
+
+    public void setDynamicFieldId(String dynamicFieldId) {
+        this.dynamicFieldId = dynamicFieldId;
+    }
+
+    public String getFieldValue() {
+        return fieldValue;
+    }
+
+    public void setFieldValue(String fieldValue) {
+        this.fieldValue = fieldValue;
+    }
+
+    public String getFieldKey() {
+        return fieldKey;
+    }
+
+    public void setFieldKey(String fieldKey) {
+        this.fieldKey = fieldKey;
+    }
+}

+ 119 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseShareInfo.java

@@ -0,0 +1,119 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+import com.jeeplus.modules.sys.entity.Workattachment;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 知识库-文件信息表实体(公共字段)
+ * @author: auto
+ * @version: 2026-04-22
+ */
+public class WorkKnowledgeBaseShareInfo extends DataEntity<WorkKnowledgeBaseShareInfo> {
+
+    private String treeNodeId;    // 所属节点id
+    private String fileName;      // 文件名
+    private String fileUrl;       // 文件地址
+    private Date createTime;      // 创建时间
+
+    /** 所属根节点id(用于查询动态字段,非数据库字段) */
+    private String rootId;
+
+    /** 文件名模糊查询 */
+    private String fileNameLike;
+
+    /** 动态字段值列表(保存时使用) */
+    private List<WorkKnowledgeBaseDynamicValueInfo> dynamicValues;
+
+    /** 动态字段扩展列Map(查询结果行转列后注入,key=fieldKey, value=fieldValue) */
+    private Map<String, Object> dynamicMap;
+
+    /** 动态字段查询条件(key=fieldId, value=queryValue) */
+    private Map<String, String> dynamicConditions;
+
+    /** 附件列表(供 attachmentManager 回显用) */
+    private List<Workattachment> attachments;
+
+    public String getTreeNodeId() {
+        return treeNodeId;
+    }
+
+    public void setTreeNodeId(String treeNodeId) {
+        this.treeNodeId = treeNodeId;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+    public String getFileUrl() {
+        return fileUrl;
+    }
+
+    public void setFileUrl(String fileUrl) {
+        this.fileUrl = fileUrl;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getRootId() {
+        return rootId;
+    }
+
+    public void setRootId(String rootId) {
+        this.rootId = rootId;
+    }
+
+    public String getFileNameLike() {
+        return fileNameLike;
+    }
+
+    public void setFileNameLike(String fileNameLike) {
+        this.fileNameLike = fileNameLike;
+    }
+
+    public List<WorkKnowledgeBaseDynamicValueInfo> getDynamicValues() {
+        return dynamicValues;
+    }
+
+    public void setDynamicValues(List<WorkKnowledgeBaseDynamicValueInfo> dynamicValues) {
+        this.dynamicValues = dynamicValues;
+    }
+
+    public Map<String, Object> getDynamicMap() {
+        return dynamicMap;
+    }
+
+    public void setDynamicMap(Map<String, Object> dynamicMap) {
+        this.dynamicMap = dynamicMap;
+    }
+
+    public Map<String, String> getDynamicConditions() {
+        return dynamicConditions;
+    }
+
+    public void setDynamicConditions(Map<String, String> dynamicConditions) {
+        this.dynamicConditions = dynamicConditions;
+    }
+
+    public List<Workattachment> getAttachments() {
+        return attachments;
+    }
+
+    public void setAttachments(List<Workattachment> attachments) {
+        this.attachments = attachments;
+    }
+}

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

@@ -0,0 +1,92 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+
+import java.util.List;
+
+/**
+ * 知识库-树形节点表实体
+ * @author: auto
+ * @version: 2026-04-22
+ */
+public class WorkKnowledgeBaseTreeInfo extends DataEntity<WorkKnowledgeBaseTreeInfo> {
+
+    private String parentId;       // 父节点id
+    private String parentIds;      // 所有父级编号
+    private String rootId;         // 根节点id
+    private String treeName;       // 节点名称
+    private Integer sort;          // 排序
+
+    /** 父节点名称(用于回显) */
+    private String parentName;
+
+    /** 动态字段配置列表(一级根节点新增/编辑时使用) */
+    private List<WorkKnowledgeBaseDynamicInfo> dynamicFields;
+
+    /** 子节点列表(树形展示用) */
+    private List<WorkKnowledgeBaseTreeInfo> children;
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getParentIds() {
+        return parentIds;
+    }
+
+    public void setParentIds(String parentIds) {
+        this.parentIds = parentIds;
+    }
+
+    public String getRootId() {
+        return rootId;
+    }
+
+    public void setRootId(String rootId) {
+        this.rootId = rootId;
+    }
+
+    public String getTreeName() {
+        return treeName;
+    }
+
+    public void setTreeName(String treeName) {
+        this.treeName = treeName;
+    }
+
+    public Integer getSort() {
+        return sort;
+    }
+
+    public void setSort(Integer sort) {
+        this.sort = sort;
+    }
+
+    public String getParentName() {
+        return parentName;
+    }
+
+    public void setParentName(String parentName) {
+        this.parentName = parentName;
+    }
+
+    public List<WorkKnowledgeBaseDynamicInfo> getDynamicFields() {
+        return dynamicFields;
+    }
+
+    public void setDynamicFields(List<WorkKnowledgeBaseDynamicInfo> dynamicFields) {
+        this.dynamicFields = dynamicFields;
+    }
+
+    public List<WorkKnowledgeBaseTreeInfo> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<WorkKnowledgeBaseTreeInfo> children) {
+        this.children = children;
+    }
+}

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

@@ -0,0 +1,200 @@
+package com.jeeplus.modules.WorkKnowledgeBase.service;
+
+import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.service.CrudService;
+import com.jeeplus.common.utils.IdGen;
+import com.jeeplus.common.utils.StringUtils;
+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.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.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 知识库-文件信息 Service
+ * @author: auto
+ * @version: 2026-04-22
+ */
+@Service
+@Transactional(readOnly = true)
+public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBaseShareInfoDao, WorkKnowledgeBaseShareInfo> {
+
+    /** 附件标识(attachmentFlag),进行隔离不同业务的附件 */
+    private static final String ATTACHMENT_FLAG = "199";
+
+    @Autowired
+    private WorkKnowledgeBaseDynamicInfoDao dynamicInfoDao;
+
+    @Autowired
+    private WorkKnowledgeBaseDynamicValueInfoDao dynamicValueInfoDao;
+
+    @Autowired
+    private WorkKnowledgeBaseTreeInfoDao treeInfoDao;
+
+    @Autowired
+    private WorkattachmentService workattachmentService;
+
+    /**
+     * 根据文件id加载附件列表(编辑表单回显用)
+     */
+    public List<Workattachment> findAttachmentsByFileId(String fileId) {
+        if (StringUtils.isBlank(fileId)) {
+            return new ArrayList<>();
+        }
+        return workattachmentService.getListByAttachmentIdAndFlag(fileId, ATTACHMENT_FLAG);
+    }
+
+    /**
+     * 根据文件id查询动态字段値列表(编辑表单回显用)
+     */
+    public List<WorkKnowledgeBaseDynamicValueInfo> findDynamicValuesByFileId(String fileId) {
+        if (StringUtils.isBlank(fileId)) {
+            return new ArrayList<>();
+        }
+        return dynamicValueInfoDao.findByFileId(fileId);
+    }
+
+    /**
+     * 根据根节点id查询动态字段配置
+     */
+    public List<WorkKnowledgeBaseDynamicInfo> findDynamicFields(String rootId) {
+        if (StringUtils.isBlank(rootId)) {
+            return new ArrayList<>();
+        }
+        return dynamicInfoDao.findByRootId(rootId);
+    }
+
+    /**
+     * 动态列表分页查询(核心方法)
+     * 使用 CASE WHEN + MAX + GROUP BY 行转列
+     * 动态字段查询条件使用 EXISTS 子查询
+     */
+    public Page<Map<String, Object>> findDynamicPage(Page<Map<String, Object>> page,
+                                                      WorkKnowledgeBaseShareInfo entity,
+                                                      List<WorkKnowledgeBaseDynamicInfo> dynamicFields,
+                                                      Map<String, String> dynamicConditions) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("entity", entity);
+        params.put("dynamicFields", dynamicFields);
+        params.put("dynamicConditions", dynamicConditions);
+        // 计算分页偏移量
+        int pageNo = page.getPageNo() > 0 ? page.getPageNo() : 1;
+        int pageSize = page.getPageSize() > 0 ? page.getPageSize() : 10;
+        params.put("offset", (pageNo - 1) * pageSize);
+        params.put("limit", pageSize);
+
+        int count = dao.findDynamicCount(params);
+        page.setCount(count);
+        page.setCountFlag(false);
+
+        if (count > 0) {
+            page.setList(dao.findDynamicList(params));
+        } else {
+            page.setList(new ArrayList<>());
+        }
+        return page;
+    }
+
+    /**
+     * 根据根节点id查询文件信息(不含动态字段,用于表单回显基础信息)
+     */
+    public WorkKnowledgeBaseShareInfo getWithDynamicValues(String id) {
+        WorkKnowledgeBaseShareInfo entity = dao.get(id);
+        return entity;
+    }
+
+    /**
+     * 保存文件信息(新增或编辑)
+     * 同步保存动态字段值(先删后增)
+     */
+    @Transactional(readOnly = false)
+    public void saveShare(WorkKnowledgeBaseShareInfo shareInfo) {
+        boolean isNew = shareInfo.getIsNewRecord();
+        
+        if (isNew) {
+            shareInfo.setId(IdGen.uuid());
+            shareInfo.preInsert();
+            dao.insert(shareInfo);
+        } else {
+            shareInfo.preUpdate();
+            dao.update(shareInfo);
+        }
+        
+        // 保存附件
+        List<Workattachment> attachments = shareInfo.getAttachments();
+        if (attachments != null) {
+            for (Workattachment attachment : attachments) {
+                if (attachment.getId() == null) {
+                    continue;
+                }
+                if (Workattachment.DEL_FLAG_NORMAL.equals(attachment.getDelFlag())) {
+                    attachment.setAttachmentId(shareInfo.getId());
+                    attachment.setAttachmentFlag(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);
+                }
+            }
+        }
+        
+        // 先逻辑删除旧的动态字段値
+        WorkKnowledgeBaseDynamicValueInfo delEntity = new WorkKnowledgeBaseDynamicValueInfo();
+        delEntity.setFileId(shareInfo.getId());
+        delEntity.preUpdate();
+        dynamicValueInfoDao.deleteByFileId(delEntity);
+
+        // 重新插入新的动态字段值
+        List<WorkKnowledgeBaseDynamicValueInfo> dynamicValues = shareInfo.getDynamicValues();
+        if (dynamicValues != null) {
+            for (WorkKnowledgeBaseDynamicValueInfo valueInfo : dynamicValues) {
+                if (StringUtils.isBlank(valueInfo.getDynamicFieldId())) {
+                    continue;
+                }
+                valueInfo.setId(IdGen.uuid());
+                valueInfo.setFileId(shareInfo.getId());
+                valueInfo.preInsert();
+                dynamicValueInfoDao.insert(valueInfo);
+            }
+        }
+    }
+
+    /**
+     * 逻辑删除文件(含动态字段值)
+     */
+    @Transactional(readOnly = false)
+    public void deleteShare(WorkKnowledgeBaseShareInfo entity) {
+        entity.preUpdate();
+        dao.deleteByLogic(entity);
+
+        // 同步逻辑删除动态字段值
+        WorkKnowledgeBaseDynamicValueInfo delVal = new WorkKnowledgeBaseDynamicValueInfo();
+        delVal.setFileId(entity.getId());
+        delVal.preUpdate();
+        dynamicValueInfoDao.deleteByFileId(delVal);
+    }
+
+    /**
+     * 根据nodeId获取rootId
+     */
+    public String getRootIdByNodeId(String nodeId) {
+        return treeInfoDao.getRootIdByNodeId(nodeId);
+    }
+}

+ 128 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseTreeService.java

@@ -0,0 +1,128 @@
+package com.jeeplus.modules.WorkKnowledgeBase.service;
+
+import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.service.CrudService;
+import com.jeeplus.common.utils.IdGen;
+import com.jeeplus.common.utils.StringUtils;
+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 org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 知识库-树形节点 Service
+ * @author: auto
+ * @version: 2026-04-22
+ */
+@Service
+@Transactional(readOnly = true)
+public class WorkKnowledgeBaseTreeService extends CrudService<WorkKnowledgeBaseTreeInfoDao, WorkKnowledgeBaseTreeInfo> {
+
+    @Autowired
+    private WorkKnowledgeBaseDynamicInfoDao dynamicInfoDao;
+
+    /**
+     * 查询所有节点(用于构建左侧树)
+     */
+    public List<WorkKnowledgeBaseTreeInfo> findAllTreeList() {
+        WorkKnowledgeBaseTreeInfo entity = new WorkKnowledgeBaseTreeInfo();
+        entity.setDelFlag("0");
+        return dao.findAllTreeList(entity);
+    }
+
+    /**
+     * 根据节点id获取根节点id
+     */
+    public String getRootIdByNodeId(String nodeId) {
+        return dao.getRootIdByNodeId(nodeId);
+    }
+
+    /**
+     * 获取单条节点数据(含动态字段列表,仅根节点有)
+     */
+    public WorkKnowledgeBaseTreeInfo getWithDynamic(String id) {
+        WorkKnowledgeBaseTreeInfo entity = dao.get(id);
+        if (entity != null && "0".equals(entity.getParentId())) {
+            // 根节点加载动态字段
+            String rootId = entity.getId();
+            List<WorkKnowledgeBaseDynamicInfo> dynamicFields = dynamicInfoDao.findByRootId(rootId);
+            entity.setDynamicFields(dynamicFields);
+        }
+        return entity;
+    }
+
+    /**
+     * 保存节点(新增或编辑),一级根节点同步维护动态字段配置
+     */
+    @Transactional(readOnly = false)
+    public void saveTree(WorkKnowledgeBaseTreeInfo treeInfo) {
+        boolean isNew = treeInfo.getIsNewRecord();
+        boolean isRoot = "0".equals(treeInfo.getParentId()) || StringUtils.isBlank(treeInfo.getParentId());
+
+        if (isNew) {
+            treeInfo.setId(IdGen.uuid());
+            if (isRoot) {
+                // 根节点:root_id = 自身id
+                treeInfo.setRootId(treeInfo.getId());
+                treeInfo.setParentId("0");
+                treeInfo.setParentIds("0,");
+            } else {
+                // 子节点:root_id 从父节点继承
+                String parentRootId = dao.getRootIdByNodeId(treeInfo.getParentId());
+                treeInfo.setRootId(StringUtils.isNotBlank(parentRootId) ? parentRootId : treeInfo.getParentId());
+                // 构建parentIds
+                WorkKnowledgeBaseTreeInfo parent = dao.get(treeInfo.getParentId());
+                if (parent != null) {
+                    treeInfo.setParentIds(parent.getParentIds() + parent.getId() + ",");
+                }
+            }
+            treeInfo.preInsert();
+            dao.insert(treeInfo);
+        } else {
+            treeInfo.preUpdate();
+            dao.update(treeInfo);
+        }
+
+        // 仅根节点维护动态字段
+        if (isRoot) {
+            String rootId = treeInfo.getId();
+            // 先逻辑删除旧的动态字段
+            WorkKnowledgeBaseDynamicInfo delEntity = new WorkKnowledgeBaseDynamicInfo();
+            delEntity.setRootId(rootId);
+            delEntity.preUpdate();
+            dynamicInfoDao.deleteByRootId(delEntity);
+
+            // 重新插入新的动态字段
+            List<WorkKnowledgeBaseDynamicInfo> dynamicFields = treeInfo.getDynamicFields();
+            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);
+                }
+            }
+        }
+    }
+
+    /**
+     * 逻辑删除节点(含所有子节点)
+     */
+    @Transactional(readOnly = false)
+    public void deleteTree(WorkKnowledgeBaseTreeInfo entity) {
+        entity.preUpdate();
+        dao.deleteByLogicWithChildren(entity);
+    }
+
+    public Page<WorkKnowledgeBaseTreeInfo> findPage(Page<WorkKnowledgeBaseTreeInfo> page, WorkKnowledgeBaseTreeInfo entity) {
+        return super.findPage(page, entity);
+    }
+}

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

@@ -0,0 +1,199 @@
+package com.jeeplus.modules.WorkKnowledgeBase.web;
+
+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.web.BaseController;
+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.service.WorkKnowledgeBaseShareService;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+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.servlet.mvc.support.RedirectAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 知识库-文件信息管理 Controller
+ * @author: auto
+ * @version: 2026-04-22
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/workKnowledgeBase/share")
+public class WorkKnowledgeBaseShareController extends BaseController {
+
+    @Autowired
+    private WorkKnowledgeBaseShareService shareService;
+
+    @ModelAttribute
+    public WorkKnowledgeBaseShareInfo get(@RequestParam(required = false) String id) {
+        WorkKnowledgeBaseShareInfo entity = null;
+        if (StringUtils.isNotBlank(id)) {
+            entity = shareService.get(id);
+        }
+        if (entity == null) {
+            entity = new WorkKnowledgeBaseShareInfo();
+        }
+        return entity;
+    }
+
+    /**
+     * 右侧列表页面(含动态字段表头和查询条件)
+     * 参数:treeNodeId(节点id),会自动查询 rootId
+     */
+    @RequiresPermissions("workKnowledgeBase:share:list")
+    @RequestMapping(value = {"list", ""})
+    public String list(WorkKnowledgeBaseShareInfo shareInfo,
+                       HttpServletRequest request, HttpServletResponse response, Model model) {
+        String treeNodeId = shareInfo.getTreeNodeId();
+        String rootId = shareInfo.getRootId();
+
+        // 通过nodeId获取rootId
+        if (StringUtils.isNotBlank(treeNodeId) && StringUtils.isBlank(rootId)) {
+            rootId = shareService.getRootIdByNodeId(treeNodeId);
+            shareInfo.setRootId(rootId);
+        }
+
+        // 查询动态字段配置
+        List<WorkKnowledgeBaseDynamicInfo> dynamicFields = new ArrayList<>();
+        if (StringUtils.isNotBlank(rootId)) {
+            dynamicFields = shareService.findDynamicFields(rootId);
+        }
+
+        // 解析动态查询条件(格式:参数名 dynamic_fieldId=value)
+        Map<String, String> dynamicConditions = new HashMap<>();
+        if (dynamicFields != null) {
+            for (WorkKnowledgeBaseDynamicInfo field : dynamicFields) {
+                String paramValue = request.getParameter("dynamic_" + field.getId());
+                if (StringUtils.isNotBlank(paramValue)) {
+                    dynamicConditions.put(field.getId(), paramValue.trim());
+                }
+            }
+        }
+
+        // 分页查询
+        Page<Map<String, Object>> page = new Page<>(request, response);
+        if (StringUtils.isNotBlank(rootId)) {
+            shareService.findDynamicPage(page, shareInfo, dynamicFields, dynamicConditions);
+        }
+
+        model.addAttribute("page", page);
+        model.addAttribute("shareInfo", shareInfo);
+        model.addAttribute("dynamicFields", dynamicFields);
+        model.addAttribute("dynamicConditions", dynamicConditions);
+        model.addAttribute("treeNodeId", treeNodeId);
+        model.addAttribute("rootId", rootId);
+        return "modules/WorkKnowledgeBase/workKnowledgeBaseShareList";
+    }
+
+    /**
+     * 新增/编辑表单页面
+     * 编辑时将动态字段已有値加载到模型中(dynValues Map)
+     */
+    @RequiresPermissions(value = {"workKnowledgeBase:share:add", "workKnowledgeBase:share:edit"})
+    @RequestMapping(value = "form")
+    public String form(WorkKnowledgeBaseShareInfo shareInfo, Model model) {
+        String rootId = shareInfo.getRootId();
+        String treeNodeId = shareInfo.getTreeNodeId();
+
+        // 编辑时若无rootId,通过nodeId查询
+        if (StringUtils.isBlank(rootId) && StringUtils.isNotBlank(treeNodeId)) {
+            rootId = shareService.getRootIdByNodeId(treeNodeId);
+            shareInfo.setRootId(rootId);
+        }
+
+        // 查询动态字段配置
+        List<WorkKnowledgeBaseDynamicInfo> dynamicFields = new ArrayList<>();
+        if (StringUtils.isNotBlank(rootId)) {
+            dynamicFields = shareService.findDynamicFields(rootId);
+        }
+
+        // 编辑时加载已有动态字段値(主键 -> 字段値 Map)
+        Map<String, String> dynValues = new HashMap<>();
+        if (StringUtils.isNotBlank(shareInfo.getId())) {
+            List<WorkKnowledgeBaseDynamicValueInfo> existValues =
+                    shareService.findDynamicValuesByFileId(shareInfo.getId());
+            if (existValues != null) {
+                for (WorkKnowledgeBaseDynamicValueInfo val : existValues) {
+                    dynValues.put(val.getDynamicFieldId(), val.getFieldValue());
+                }
+            }
+        }
+
+        // 编辑时加载已有附件列表(回显用)
+        if (StringUtils.isNotBlank(shareInfo.getId())) {
+            shareInfo.setAttachments(shareService.findAttachmentsByFileId(shareInfo.getId()));
+        }
+
+        model.addAttribute("entity", shareInfo);
+        model.addAttribute("dynamicFields", dynamicFields);
+        model.addAttribute("rootId", rootId);
+        model.addAttribute("dynValues", dynValues);
+        return "modules/WorkKnowledgeBase/workKnowledgeBaseShareForm";
+    }
+
+    /**
+     * 保存文件信息(含动态字段值)
+     * 动态字段值以 JSON 数组字符串形式提交:dynamicValuesJson
+     */
+    @RequiresPermissions(value = {"workKnowledgeBase:share:add", "workKnowledgeBase:share:edit"})
+    @RequestMapping(value = "save")
+    public String save(WorkKnowledgeBaseShareInfo shareInfo,
+                       @RequestParam(required = false) String dynamicValuesJson,
+                       Model model, RedirectAttributes redirectAttributes) {
+        if (!beanValidator(model, shareInfo)) {
+            return form(shareInfo, model);
+        }
+        try {
+            // 解析动态字段值
+            if (StringUtils.isNotBlank(dynamicValuesJson)) {
+                List<WorkKnowledgeBaseDynamicValueInfo> dynamicValues =
+                        JSON.parseArray(dynamicValuesJson, WorkKnowledgeBaseDynamicValueInfo.class);
+                shareInfo.setDynamicValues(dynamicValues);
+            }
+            shareService.saveShare(shareInfo);
+            addMessage(redirectAttributes, "保存知识库文件信息成功");
+        } catch (Exception e) {
+            addMessage(redirectAttributes, "保存失败:" + e.getMessage());
+        }
+        return "redirect:" + Global.getAdminPath() + "/workKnowledgeBase/share/list?treeNodeId=" + shareInfo.getTreeNodeId() + "&rootId=" + shareInfo.getRootId();
+    }
+
+    /**
+     * 删除文件(逻辑删除,Ajax)
+     */
+    @RequiresPermissions("workKnowledgeBase:share:del")
+    @RequestMapping(value = "delete")
+    @ResponseBody
+    public Map<String, Object> delete(WorkKnowledgeBaseShareInfo shareInfo) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            shareService.deleteShare(shareInfo);
+            result.put("success", true);
+            result.put("message", "删除成功");
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", "删除失败:" + e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 根据rootId查询动态字段(Ajax,供表单动态渲染)
+     */
+    @RequestMapping(value = "getDynamicFields")
+    @ResponseBody
+    public List<WorkKnowledgeBaseDynamicInfo> getDynamicFields(@RequestParam String rootId) {
+        return shareService.findDynamicFields(rootId);
+    }
+}

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

@@ -0,0 +1,149 @@
+package com.jeeplus.modules.WorkKnowledgeBase.web;
+
+import com.jeeplus.common.config.Global;
+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 org.apache.shiro.authz.annotation.RequiresPermissions;
+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.servlet.mvc.support.RedirectAttributes;
+
+import com.alibaba.fastjson.JSON;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 知识库-树形节点管理 Controller
+ * @author: auto
+ * @version: 2026-04-22
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/workKnowledgeBase/tree")
+public class WorkKnowledgeBaseTreeController extends BaseController {
+
+    @Autowired
+    private WorkKnowledgeBaseTreeService treeService;
+
+    @ModelAttribute
+    public WorkKnowledgeBaseTreeInfo get(@RequestParam(required = false) String id) {
+        WorkKnowledgeBaseTreeInfo entity = null;
+        if (StringUtils.isNotBlank(id)) {
+            entity = treeService.get(id);
+        }
+        if (entity == null) {
+            entity = new WorkKnowledgeBaseTreeInfo();
+        }
+        return entity;
+    }
+
+    /**
+     * 主页面(左树右表布局)
+     */
+    @RequiresPermissions("workKnowledgeBase:tree:list")
+    @RequestMapping(value = {"", "index"})
+    public String index(Model model) {
+        List<WorkKnowledgeBaseTreeInfo> treeList = treeService.findAllTreeList();
+        model.addAttribute("treeList", treeList);
+        return "modules/WorkKnowledgeBase/workKnowledgeBaseIndex";
+    }
+
+    /**
+     * 查询所有树节点(Ajax,用于刷新左侧树)
+     */
+    @RequiresPermissions("workKnowledgeBase:tree:list")
+    @RequestMapping(value = "treeData")
+    @ResponseBody
+    public List<WorkKnowledgeBaseTreeInfo> treeData() {
+        return treeService.findAllTreeList();
+    }
+
+    /**
+     * 根据节点id获取 root_id(Ajax)
+     */
+    @RequestMapping(value = "getRootId")
+    @ResponseBody
+    public Map<String, Object> getRootId(@RequestParam String nodeId) {
+        Map<String, Object> result = new HashMap<>();
+        String rootId = treeService.getRootIdByNodeId(nodeId);
+        result.put("rootId", rootId);
+        result.put("success", StringUtils.isNotBlank(rootId));
+        return result;
+    }
+
+    /**
+     * 新增/编辑节点表单页面
+     */
+    @RequiresPermissions(value = {"workKnowledgeBase:tree:add", "workKnowledgeBase:tree:edit"})
+    @RequestMapping(value = "form")
+    public String form(WorkKnowledgeBaseTreeInfo treeInfo, Model model) {
+        // 如果有id,加载含动态字段的完整数据
+        if (StringUtils.isNotBlank(treeInfo.getId())) {
+            treeInfo = treeService.getWithDynamic(treeInfo.getId());
+        }
+        // 如果有parentId,查询父节点名称
+        if (StringUtils.isNotBlank(treeInfo.getParentId()) && !"0".equals(treeInfo.getParentId())) {
+            WorkKnowledgeBaseTreeInfo parent = treeService.get(treeInfo.getParentId());
+            if (parent != null) {
+                model.addAttribute("parentName", parent.getTreeName());
+            }
+        }
+        model.addAttribute("workKnowledgeBaseTreeInfo", treeInfo);
+        return "modules/WorkKnowledgeBase/workKnowledgeBaseTreeForm";
+    }
+
+    /**
+     * 保存节点
+     * 动态字段通过 dynamicFieldsJson 参数传入
+     */
+    @RequiresPermissions(value = {"workKnowledgeBase:tree:add", "workKnowledgeBase:tree:edit"})
+    @RequestMapping(value = "save")
+    public String save(WorkKnowledgeBaseTreeInfo treeInfo,
+                       @RequestParam(required = false) String dynamicFieldsJson,
+                       Model model, RedirectAttributes redirectAttributes) {
+        if (!beanValidator(model, treeInfo)) {
+            return form(treeInfo, model);
+        }
+        try {
+            // 解析动态字段JSON
+            if (StringUtils.isNotBlank(dynamicFieldsJson)) {
+                List<WorkKnowledgeBaseDynamicInfo> dynamicFields =
+                        JSON.parseArray(dynamicFieldsJson, WorkKnowledgeBaseDynamicInfo.class);
+                treeInfo.setDynamicFields(dynamicFields);
+            } else {
+                treeInfo.setDynamicFields(new ArrayList<>());
+            }
+            treeService.saveTree(treeInfo);
+            addMessage(redirectAttributes, "保存知识库节点成功");
+        } catch (Exception e) {
+            addMessage(redirectAttributes, "保存失败:" + e.getMessage());
+        }
+        return "redirect:" + Global.getAdminPath() + "/workKnowledgeBase/tree/index";
+    }
+
+    /**
+     * 删除节点(逻辑删除,含子节点)
+     */
+    @RequiresPermissions("workKnowledgeBase:tree:del")
+    @RequestMapping(value = "delete")
+    @ResponseBody
+    public Map<String, Object> delete(WorkKnowledgeBaseTreeInfo treeInfo) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            treeService.deleteTree(treeInfo);
+            result.put("success", true);
+            result.put("message", "删除成功");
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", "删除失败:" + e.getMessage());
+        }
+        return result;
+    }
+}

File diff suppressed because it is too large
+ 2886 - 0
src/main/java/com/jeeplus/modules/projectPerformanceDatabase/entity/RuralProjectRecordsPerformance.java


+ 27 - 3
src/main/java/com/jeeplus/modules/projectPerformanceDatabase/web/ProjectPerformanceController.java

@@ -2,11 +2,14 @@ package com.jeeplus.modules.projectPerformanceDatabase.web;
 
 import com.jeeplus.common.config.Global;
 import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.utils.DateUtils;
 import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.common.utils.excel.ExportExcel;
 import com.jeeplus.common.web.BaseController;
 import com.jeeplus.modules.projectEngineering.entity.ProjectEngineeringInfo;
 import com.jeeplus.modules.projectEngineering.service.ProjectEngineeringService;
 import com.jeeplus.modules.projectPerformanceDatabase.entity.ProjectPerformanceDatabase;
+import com.jeeplus.modules.projectPerformanceDatabase.entity.RuralProjectRecordsPerformance;
 import com.jeeplus.modules.projectPerformanceDatabase.service.ProjectPerformanceDatabaseService;
 import com.jeeplus.modules.projectPerformanceDatabase.service.ProjectPerformanceService;
 import com.jeeplus.modules.ruralprojectrecords.entity.RuralProjectRecords;
@@ -24,7 +27,9 @@ import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.ModelAttribute;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -34,9 +39,9 @@ import java.util.List;
 import java.util.Map;
 
 /**
- * 知识分享列表类型controller
+ * 项目设置业绩库类型controller
  * @author: 徐滕
- * @version: 2022-09-29 08:31
+ * @version: 2026-04-20 08:31
  */
 @Controller
 @RequestMapping(value = "${adminPath}/projectPerformance")
@@ -169,7 +174,7 @@ public class ProjectPerformanceController extends BaseController {
     /**
      * 电子归档批量驳回
      */
-    //@RequiresPermissions("ruralProject:ruralProjectMessageAll:reportBatchReject")
+    @RequiresPermissions("projectPerformance:add")
     @RequestMapping(value = "saveProjectPerformance")
     public String saveProjectPerformance(@RequestParam String listId, @RequestParam String projectPerformanceDatabaseId, HttpServletResponse response, Model model) {
         Map<String,Object> map = new HashMap<>();
@@ -188,4 +193,23 @@ public class ProjectPerformanceController extends BaseController {
         return "redirect:"+ Global.getAdminPath()+"/projectPerformance/?repage";
     }
 
+
+
+    /**
+     * 导出excel文件
+     */
+    @RequiresPermissions("projectPerformance:export")
+    @RequestMapping(value = "export", method= RequestMethod.POST)
+    public String exportFile(RuralProjectRecords projectRecords, HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirectAttributes) {
+        try {
+            String fileName = "项目业绩信息"+ DateUtils.getDate("yyyyMMddHHmmss")+".xlsx";
+            Page<RuralProjectRecords> page = service.findPage(new Page<RuralProjectRecords>(request, response, -1), projectRecords);
+            new ExportExcel("项目业绩信息", RuralProjectRecordsPerformance.class).setDataList(page.getList()).write(response, fileName).dispose();
+            return null;
+        } catch (Exception e) {
+            addMessage(redirectAttributes, "导出项目业绩信息记录失败!失败信息:"+e.getMessage());
+        }
+        return "redirect:"+Global.getAdminPath()+"/projectPerformance/?repage";
+    }
+
 }

+ 23 - 9
src/main/java/com/jeeplus/modules/workcontractinfo/service/WorkContractInfoTookDisposeService.java

@@ -406,15 +406,29 @@ public class WorkContractInfoTookDisposeService extends CrudService<WorkContract
 				}*/
 				//合同审批完成后随即发起归档申请
 				//合同审批完成后随即发起归档申请
-				WorkContractRecord workContractRecord = new WorkContractRecord();
-				workContractRecord.setStatus("2");
-				workContractRecord.setOfficeId(UserUtils.getSelectOffice().getId());
-				workContractRecord.setCompanyId(UserUtils.getSelectCompany().getId());
-				workContractRecord.setWorkContractInfo(workContractInfo);
-				Map<String, Object> variables = Maps.newHashMap();
-				String processInstanceId ="";
-				workContractRecordService.saveZjlStart(workContractRecord,variables,processInstanceId);
-				workContractInfo.setContractRecordState("2");
+				//如果是苏州分公司的合同,此处直接设置合同归档状态为苏州无需归档,无需走本地归档流程
+				Office createOffice = officeService.get(workContractInfo.getOfficeId());
+				if (createOffice.getParentIds().contains("49f5d751f986479b94f0547b6daa38e0")) {
+					WorkContractRecord workContractRecord = new WorkContractRecord();
+					workContractRecord.setStatus("15");
+					workContractRecord.setOfficeId(createOffice.getId());
+					workContractRecord.setCompanyId(UserUtils.getSelectCompany().getId());
+					workContractRecord.setWorkContractInfo(workContractInfo);
+					workContractRecord.setAccomplishDate(new Date());
+					workContractRecordService.save(workContractRecord);
+
+					workContractInfo.setContrractRecordStatus("15");
+				}else{
+					WorkContractRecord workContractRecord = new WorkContractRecord();
+					workContractRecord.setStatus("2");
+					workContractRecord.setOfficeId(UserUtils.getSelectOffice().getId());
+					workContractRecord.setCompanyId(UserUtils.getSelectCompany().getId());
+					workContractRecord.setWorkContractInfo(workContractInfo);
+					Map<String, Object> variables = Maps.newHashMap();
+					String processInstanceId ="";
+					workContractRecordService.saveZjlStart(workContractRecord,variables,processInstanceId);
+					workContractInfo.setContractRecordState("2");
+				}
 
 			} else {
 				WorkProjectNotify notify = new WorkProjectNotify();

+ 2 - 1
src/main/java/com/jeeplus/modules/workcontractinfo/web/WorkContractInfoController.java

@@ -22,7 +22,6 @@ import com.jeeplus.modules.act.service.ActTaskService;
 import com.jeeplus.modules.act.utils.ActUtils;
 import com.jeeplus.modules.alterinfo.entity.AlterInfo;
 import com.jeeplus.modules.alterinfo.service.AlterInfoService;
-import com.jeeplus.modules.ruralprojectrecords.entity.RuralProjectRecords;
 import com.jeeplus.modules.sys.dao.OfficeDao;
 import com.jeeplus.modules.sys.entity.Office;
 import com.jeeplus.modules.sys.entity.Role;
@@ -2403,6 +2402,8 @@ public class WorkContractInfoController extends BaseController {
                 }
                 if("5".equals(info.getContrractRecordStatus())){
                     info.setContrractRecordStatus("已归档");
+                }else if("15".equals(info.getContrractRecordStatus())){
+                    info.setContrractRecordStatus("苏州无需归档");
                 }else{
                     info.setContrractRecordStatus("未归档");
                 }

+ 1 - 1
src/main/java/com/jeeplus/modules/workinvoice/service/WorkInvoiceService.java

@@ -1863,7 +1863,7 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 							//notifyRole = "财务主任审批";
 							notifyRole = "审批通过";
 							workActivityProcess.setIsApproval("1");
-							if(1 == workInvoice.getIsOmsBilling()){
+							if(null == workInvoice.getIsOmsBilling() || 1 == workInvoice.getIsOmsBilling()){
 								OMS_ENABLED = false;
 							}
 							if(OMS_ENABLED){

+ 118 - 0
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseDynamicInfoDao.xml

@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseDynamicInfoDao">
+
+    <sql id="dynamicColumns">
+        a.id          AS "id",
+        a.root_id     AS "rootId",
+        a.field_key   AS "fieldKey",
+        a.field_label AS "fieldLabel",
+        a.field_type  AS "fieldType",
+        a.sort        AS "sort",
+        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"
+    </sql>
+
+    <select id="get" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo">
+        SELECT <include refid="dynamicColumns"/>
+        FROM work_knowledge_base_dynamic_info a
+        WHERE a.id = #{id}
+    </select>
+
+    <select id="findList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo">
+        SELECT <include refid="dynamicColumns"/>
+        FROM work_knowledge_base_dynamic_info a
+        <where>
+            a.del_flag = #{DEL_FLAG_NORMAL}
+            <if test="rootId != null and rootId != ''">
+                AND a.root_id = #{rootId}
+            </if>
+        </where>
+        ORDER BY a.sort ASC, a.create_date ASC
+    </select>
+
+    <!-- 根据根节点id查询动态字段列表 -->
+    <select id="findByRootId" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo">
+        SELECT <include refid="dynamicColumns"/>
+        FROM work_knowledge_base_dynamic_info a
+        WHERE a.root_id = #{rootId}
+          AND a.del_flag = '0'
+        ORDER BY a.sort ASC, a.create_date ASC
+    </select>
+
+    <select id="findUniqueByProperty" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo">
+        SELECT <include refid="dynamicColumns"/>
+        FROM work_knowledge_base_dynamic_info a
+        WHERE ${propertyName} = #{value} AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <select id="findListByUser" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo">
+        SELECT <include refid="dynamicColumns"/>
+        FROM work_knowledge_base_dynamic_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.sort ASC
+    </select>
+
+    <select id="findAllList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo">
+        SELECT <include refid="dynamicColumns"/>
+        FROM work_knowledge_base_dynamic_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.sort ASC
+    </select>
+
+    <select id="queryCount" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_dynamic_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+    </select>
+
+    <insert id="insert">
+        INSERT INTO work_knowledge_base_dynamic_info (
+            id, root_id, field_key, field_label, field_type, sort,
+            create_by, create_date, update_by, update_date, remarks, del_flag
+        ) VALUES (
+            #{id}, #{rootId}, #{fieldKey}, #{fieldLabel}, #{fieldType}, #{sort},
+            #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks}, #{delFlag}
+        )
+    </insert>
+
+    <update id="update">
+        UPDATE work_knowledge_base_dynamic_info SET
+            field_key   = #{fieldKey},
+            field_label = #{fieldLabel},
+            field_type  = #{fieldType},
+            sort        = #{sort},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate},
+            remarks     = #{remarks}
+        WHERE id = #{id}
+    </update>
+
+    <delete id="delete">
+        DELETE FROM work_knowledge_base_dynamic_info WHERE id = #{id}
+    </delete>
+
+    <update id="deleteByLogic">
+        UPDATE work_knowledge_base_dynamic_info SET
+            del_flag    = #{DEL_FLAG_DELETE},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 根据根节点id逻辑删除所有动态字段 -->
+    <update id="deleteByRootId">
+        UPDATE work_knowledge_base_dynamic_info SET
+            del_flag    = '1',
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE root_id = #{rootId}
+          AND del_flag = '0'
+    </update>
+
+</mapper>

+ 116 - 0
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseDynamicValueInfoDao.xml

@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseDynamicValueInfoDao">
+
+    <sql id="valueColumns">
+        a.id               AS "id",
+        a.file_id          AS "fileId",
+        a.dynamic_field_id AS "dynamicFieldId",
+        a.field_value      AS "fieldValue",
+        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"
+    </sql>
+
+    <select id="get" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicValueInfo">
+        SELECT <include refid="valueColumns"/>
+        FROM work_knowledge_base_dynamic_value_info a
+        WHERE a.id = #{id}
+    </select>
+
+    <select id="findList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicValueInfo">
+        SELECT <include refid="valueColumns"/>
+        FROM work_knowledge_base_dynamic_value_info a
+        <where>
+            a.del_flag = #{DEL_FLAG_NORMAL}
+            <if test="fileId != null and fileId != ''">
+                AND a.file_id = #{fileId}
+            </if>
+            <if test="dynamicFieldId != null and dynamicFieldId != ''">
+                AND a.dynamic_field_id = #{dynamicFieldId}
+            </if>
+        </where>
+        ORDER BY a.create_date ASC
+    </select>
+
+    <select id="findUniqueByProperty" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicValueInfo">
+        SELECT <include refid="valueColumns"/>
+        FROM work_knowledge_base_dynamic_value_info a
+        WHERE ${propertyName} = #{value} AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <select id="findListByUser" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicValueInfo">
+        SELECT <include refid="valueColumns"/>
+        FROM work_knowledge_base_dynamic_value_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.create_date ASC
+    </select>
+
+    <select id="findAllList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicValueInfo">
+        SELECT <include refid="valueColumns"/>
+        FROM work_knowledge_base_dynamic_value_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.create_date ASC
+    </select>
+
+    <select id="queryCount" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_dynamic_value_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+    </select>
+
+    <insert id="insert">
+        INSERT INTO work_knowledge_base_dynamic_value_info (
+            id, file_id, dynamic_field_id, field_value,
+            create_by, create_date, update_by, update_date, remarks, del_flag
+        ) VALUES (
+            #{id}, #{fileId}, #{dynamicFieldId}, #{fieldValue},
+            #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks}, #{delFlag}
+        )
+    </insert>
+
+    <update id="update">
+        UPDATE work_knowledge_base_dynamic_value_info SET
+            field_value = #{fieldValue},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate},
+            remarks     = #{remarks}
+        WHERE id = #{id}
+    </update>
+
+    <delete id="delete">
+        DELETE FROM work_knowledge_base_dynamic_value_info WHERE id = #{id}
+    </delete>
+
+    <update id="deleteByLogic">
+        UPDATE work_knowledge_base_dynamic_value_info SET
+            del_flag    = #{DEL_FLAG_DELETE},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 根据文件id逻辑删除所有动态字段值 -->
+    <update id="deleteByFileId">
+        UPDATE work_knowledge_base_dynamic_value_info SET
+            del_flag    = '1',
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE file_id = #{fileId}
+          AND del_flag = '0'
+    </update>
+
+    <!-- 根据文件id查询所有动态字段值 -->
+    <select id="findByFileId" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicValueInfo">
+        SELECT <include refid="valueColumns"/>
+        FROM work_knowledge_base_dynamic_value_info a
+        WHERE a.file_id = #{fileId}
+          AND a.del_flag = '0'
+        ORDER BY a.create_date ASC
+    </select>
+
+</mapper>

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

@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseShareInfoDao">
+
+    <sql id="shareColumns">
+        a.id            AS "id",
+        a.tree_node_id  AS "treeNodeId",
+        a.file_name     AS "fileName",
+        a.file_url      AS "fileUrl",
+        a.create_time   AS "createTime",
+        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"
+    </sql>
+
+    <!-- 单条查询 -->
+    <select id="get" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseShareInfo">
+        SELECT <include refid="shareColumns"/>
+        FROM work_knowledge_base_share_info a
+        WHERE a.id = #{id}
+    </select>
+
+    <!-- 通用findList(不带动态列) -->
+    <select id="findList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseShareInfo">
+        SELECT <include refid="shareColumns"/>
+        FROM work_knowledge_base_share_info a
+        <where>
+            a.del_flag = #{DEL_FLAG_NORMAL}
+            <if test="treeNodeId != null and treeNodeId != ''">
+                AND a.tree_node_id = #{treeNodeId}
+            </if>
+            <if test="fileName != null and fileName != ''">
+                AND a.file_name LIKE CONCAT('%',#{fileName},'%')
+            </if>
+        </where>
+        ORDER BY a.create_date DESC
+    </select>
+
+    <!-- 根据节点id查询文件列表 -->
+    <select id="findByTreeNodeId" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseShareInfo">
+        SELECT <include refid="shareColumns"/>
+        FROM work_knowledge_base_share_info a
+        WHERE a.tree_node_id = #{treeNodeId}
+          AND a.del_flag = '0'
+        ORDER BY a.create_date DESC
+    </select>
+
+    <!--
+    =================================================================
+    动态列表查询(核心 SQL)
+    规则:
+      1. 动态列使用 CASE WHEN + MAX + GROUP BY 行转列
+      2. 动态字段查询条件使用 EXISTS 子查询,禁止写在主 WHERE 中
+    =================================================================
+    -->
+    <select id="findDynamicList" resultType="java.util.Map">
+        SELECT
+            a.id                                                  AS "id",
+            a.tree_node_id                                        AS "treeNodeId",
+            a.file_name                                           AS "fileName",
+            a.file_url                                            AS "fileUrl",
+            DATE_FORMAT(a.create_time,'%Y-%m-%d %H:%i:%s')       AS "createTime",
+            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"
+            <!-- 动态列:CASE WHEN + MAX + GROUP BY -->
+            <if test="dynamicFields != null and dynamicFields.size() > 0">
+                <foreach collection="dynamicFields" item="field" separator="">
+                    ,MAX(CASE WHEN v.dynamic_field_id = #{field.id} THEN v.field_value ELSE NULL END) AS "dynamic_${field.fieldKey}"
+                </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'
+        <where>
+            a.del_flag = '0'
+            <!-- 固定查询:节点id(通过根节点下所有节点查询) -->
+            <if test="entity.rootId != null and entity.rootId != ''">
+                AND a.tree_node_id IN (
+                    SELECT t.id FROM work_knowledge_base_tree_info t
+                    WHERE (t.id = #{entity.rootId} OR t.root_id = #{entity.rootId})
+                      AND t.del_flag = '0'
+                )
+            </if>
+            <!-- 固定查询:文件名模糊查询 -->
+            <if test="entity.fileName != null and entity.fileName != ''">
+                AND a.file_name LIKE CONCAT('%', #{entity.fileName}, '%')
+            </if>
+            <!-- 动态字段查询条件:EXISTS 子查询(禁止写在主WHERE中) -->
+            <if test="dynamicConditions != null">
+                <foreach collection="dynamicConditions" index="fieldId" item="queryVal">
+                    <if test="queryVal != null and queryVal != ''">
+                        AND EXISTS (
+                            SELECT 1
+                            FROM work_knowledge_base_dynamic_value_info ec
+                            WHERE ec.file_id = a.id
+                              AND ec.dynamic_field_id = #{fieldId}
+                              AND ec.field_value LIKE CONCAT('%', #{queryVal}, '%')
+                              AND ec.del_flag = '0'
+                        )
+                    </if>
+                </foreach>
+            </if>
+        </where>
+        GROUP BY a.id, a.tree_node_id, a.file_name, a.file_url, a.create_time,
+                 a.create_by, a.create_date, a.remarks
+        ORDER BY a.create_date DESC
+        <if test="offset != null and limit != null">
+            LIMIT #{offset}, #{limit}
+        </if>
+    </select>
+
+    <!-- 动态列表查询总数 -->
+    <select id="findDynamicCount" resultType="java.lang.Integer">
+        SELECT COUNT(DISTINCT a.id)
+        FROM work_knowledge_base_share_info a
+        <where>
+            a.del_flag = '0'
+            <if test="entity.rootId != null and entity.rootId != ''">
+                AND a.tree_node_id IN (
+                    SELECT t.id FROM work_knowledge_base_tree_info t
+                    WHERE (t.id = #{entity.rootId} OR t.root_id = #{entity.rootId})
+                      AND t.del_flag = '0'
+                )
+            </if>
+            <if test="entity.fileName != null and entity.fileName != ''">
+                AND a.file_name LIKE CONCAT('%', #{entity.fileName}, '%')
+            </if>
+            <!-- 动态字段查询条件:EXISTS 子查询 -->
+            <if test="dynamicConditions != null">
+                <foreach collection="dynamicConditions" index="fieldId" item="queryVal">
+                    <if test="queryVal != null and queryVal != ''">
+                        AND EXISTS (
+                            SELECT 1
+                            FROM work_knowledge_base_dynamic_value_info ec
+                            WHERE ec.file_id = a.id
+                              AND ec.dynamic_field_id = #{fieldId}
+                              AND ec.field_value LIKE CONCAT('%', #{queryVal}, '%')
+                              AND ec.del_flag = '0'
+                        )
+                    </if>
+                </foreach>
+            </if>
+        </where>
+    </select>
+
+    <select id="findUniqueByProperty" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseShareInfo">
+        SELECT <include refid="shareColumns"/>
+        FROM work_knowledge_base_share_info a
+        WHERE ${propertyName} = #{value} AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <select id="findListByUser" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseShareInfo">
+        SELECT <include refid="shareColumns"/>
+        FROM work_knowledge_base_share_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.create_date DESC
+    </select>
+
+    <select id="findAllList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseShareInfo">
+        SELECT <include refid="shareColumns"/>
+        FROM work_knowledge_base_share_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.create_date DESC
+    </select>
+
+    <select id="queryCount" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_share_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+    </select>
+
+    <!-- 插入 -->
+    <insert id="insert">
+        INSERT INTO work_knowledge_base_share_info (
+            id, tree_node_id, file_name, file_url, create_time,
+            create_by, create_date, update_by, update_date, remarks, del_flag
+        ) VALUES (
+            #{id}, #{treeNodeId}, #{fileName}, #{fileUrl}, NOW(),
+            #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks}, #{delFlag}
+        )
+    </insert>
+
+    <!-- 更新 -->
+    <update id="update">
+        UPDATE work_knowledge_base_share_info SET
+            file_name   = #{fileName},
+            file_url    = #{fileUrl},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate},
+            remarks     = #{remarks}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 物理删除 -->
+    <delete id="delete">
+        DELETE FROM work_knowledge_base_share_info WHERE id = #{id}
+    </delete>
+
+    <!-- 逻辑删除 -->
+    <update id="deleteByLogic">
+        UPDATE work_knowledge_base_share_info SET
+            del_flag    = #{DEL_FLAG_DELETE},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE id = #{id}
+    </update>
+
+</mapper>

+ 130 - 0
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseTreeInfoDao.xml

@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseTreeInfoDao">
+
+    <sql id="treeColumns">
+        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",
+        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"
+    </sql>
+
+    <!-- 根据id获取单条 -->
+    <select id="get" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo">
+        SELECT <include refid="treeColumns"/>
+        FROM work_knowledge_base_tree_info a
+        WHERE a.id = #{id}
+    </select>
+
+    <!-- 通用findList(不含子节点) -->
+    <select id="findList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo">
+        SELECT <include refid="treeColumns"/>
+        FROM work_knowledge_base_tree_info a
+        <where>
+            a.del_flag = #{DEL_FLAG_NORMAL}
+            <if test="treeName != null and treeName != ''">
+                AND a.tree_name LIKE CONCAT('%',#{treeName},'%')
+            </if>
+        </where>
+        ORDER BY a.sort ASC, a.create_date DESC
+    </select>
+
+    <!-- 查询全部树节点(用于左侧树构建) -->
+    <select id="findAllTreeList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo">
+        SELECT <include refid="treeColumns"/>
+        FROM work_knowledge_base_tree_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.sort ASC, a.create_date ASC
+    </select>
+
+    <!-- 根据节点id查询根节点id -->
+    <select id="getRootIdByNodeId" resultType="java.lang.String">
+        SELECT root_id
+        FROM work_knowledge_base_tree_info
+        WHERE id = #{nodeId}
+          AND del_flag = '0'
+    </select>
+
+    <!-- 根据entity findUniqueByProperty -->
+    <select id="findUniqueByProperty" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo">
+        SELECT <include refid="treeColumns"/>
+        FROM work_knowledge_base_tree_info a
+        WHERE ${propertyName} = #{value} AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <select id="findListByUser" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo">
+        SELECT <include refid="treeColumns"/>
+        FROM work_knowledge_base_tree_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.sort ASC
+    </select>
+
+    <select id="findAllList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseTreeInfo">
+        SELECT <include refid="treeColumns"/>
+        FROM work_knowledge_base_tree_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.sort ASC
+    </select>
+
+    <select id="queryCount" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_tree_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+    </select>
+
+    <!-- 插入 -->
+    <insert id="insert">
+        INSERT INTO work_knowledge_base_tree_info (
+            id, parent_id, parent_ids, root_id, tree_name, sort,
+            create_by, create_date, update_by, update_date, remarks, del_flag
+        ) VALUES (
+            #{id}, #{parentId}, #{parentIds}, #{rootId}, #{treeName}, #{sort},
+            #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks}, #{delFlag}
+        )
+    </insert>
+
+    <!-- 更新 -->
+    <update id="update">
+        UPDATE work_knowledge_base_tree_info SET
+            tree_name   = #{treeName},
+            sort        = #{sort},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate},
+            remarks     = #{remarks}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 物理删除(不建议使用) -->
+    <delete id="delete">
+        DELETE FROM work_knowledge_base_tree_info WHERE id = #{id}
+    </delete>
+
+    <!-- 逻辑删除(单条) -->
+    <update id="deleteByLogic">
+        UPDATE work_knowledge_base_tree_info SET
+            del_flag    = #{DEL_FLAG_DELETE},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 逻辑删除(含所有子节点,通过 parent_ids LIKE) -->
+    <update id="deleteByLogicWithChildren">
+        UPDATE work_knowledge_base_tree_info SET
+            del_flag    = '1',
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE id = #{id}
+           OR parent_ids LIKE CONCAT('%,', #{id}, ',%')
+    </update>
+
+</mapper>

+ 8 - 0
src/main/resources/mappings/modules/projectPerformanceDatabase/ProjectPerformanceDao.xml

@@ -29,6 +29,7 @@
 		SELECT
 		a.id AS "id",
 		a.create_by AS "createBy.id",
+		(select name from sys_user user where user.id=a.create_by) AS "createByName",
 		a.create_date AS "createDate",
 		a.update_by AS "updateBy.id",
 		a.update_date AS "updateDate",
@@ -48,6 +49,7 @@
 		a.process_instance_id AS "processInstanceId",
 		a.company_id AS "company.id",
 		a.office_id AS "office.id",
+		o.name AS "createByOffice",
 		a.alter_process_id AS "alterProcessId",
 		a.province,
 		a.city,
@@ -114,6 +116,12 @@
 		,prd.ZiXunShouRu as "money"
 		,ppd.value as "projectPerformanceName"
 
+		,ifnull(prd.review_fee ,"") as "reviewFee"
+		,ifnull(prd.approval_fee ,"") as "approvalFee"
+		,ifnull(prd.verify_fee ,"") as "verifyFee"
+		,ifnull(prd.verify_rate ,"") as "verifyRate"
+		,wci.contract_num as "workContractInfo.contractNum"
+
 		FROM rural_project_records a
 		LEFT JOIN sys_area area ON area.id = a.area_id
 

+ 1 - 1
src/main/resources/mappings/modules/projectPerformanceDatabase/ProjectPerformanceDatabaseDao.xml

@@ -40,7 +40,7 @@
 		<where>
 			a.del_flag = #{DEL_FLAG_NORMAL}
             <if test="value != null and value != ''">
-                AND a.value = #{value}
+				and a.value like CONCAT('%',#{value},'%')
             </if>
 		</where>
 		<choose>

+ 3 - 0
src/main/resources/mappings/modules/workcontractinfo/WorkContractInfoDao.xml

@@ -1254,6 +1254,9 @@
 			<if test="projectLeaderIds != null and projectLeaderIds!= ''">
 				,project_leader_ids = #{projectLeaderIds}
 			</if>
+			<if test="contrractRecordStatus != null and contrractRecordStatus!= ''">
+				,contract_record_state = #{contrractRecordStatus}
+			</if>
 		WHERE id = #{id}
 	</update>
 

+ 1 - 1
src/main/webapp/static/common/css/style.css

@@ -8515,7 +8515,7 @@ a.op-btn-download:hover{
     border-radius: 5px;
 }
 .new-status-label{
-    width: 72px;
+    width: 80px;
     border-radius: 5px;
 }
 .status-label-signed,.new-status-label{

+ 1 - 0
src/main/webapp/static/common/jeeplus.js

@@ -569,6 +569,7 @@ function getRuralProjectArchiveState(id)
         case "7":result.label = "signed";result.status="超期归档";break;
         case "8":result.label = "changing";result.status="变更中";break;
         case "10":result.label = "signed";result.status="无需归档";result.action = false;break;
+        case "15":result.label = "signed";result.status="苏州无需归档";result.action = false;break;
         default:
             result.label = "unknown";result.status="未知";break;
     }

+ 1 - 1
src/main/webapp/webpage/include/head.jsp

@@ -36,7 +36,7 @@
 
 <!-- jeeplus -->
 <link href="${ctxStatic}/common/jeeplus.css" type="text/css" rel="stylesheet" />
-<script src="${ctxStatic}/common/jeeplus.js?26" type="text/javascript"></script>
+<script src="${ctxStatic}/common/jeeplus.js?27" type="text/javascript"></script>
 <script type="text/javascript" src="${ctxStatic}/common/openShow.js"></script>
 
 <!-- jquery ui -->

+ 270 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseIndex.jsp

@@ -0,0 +1,270 @@
+<%@ 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">
+        var currentNodeId = '';
+        var currentRootId = '';
+
+        $(document).ready(function() {
+            // 初始化树形菜单点击事件
+            bindTreeClick();
+        });
+
+        /** 绑定树节点点击事件 */
+        function bindTreeClick() {
+            $('.tree-node-item').on('click', function() {
+                $('.tree-node-item').removeClass('active');
+                $(this).addClass('active');
+                currentNodeId = $(this).data('id');
+                currentRootId = $(this).data('root-id');
+                // 加载右侧列表
+                loadRightList(currentNodeId, currentRootId);
+            });
+
+            // 展开/收起子节点
+            $('.tree-toggle').on('click', function(e) {
+                e.stopPropagation();
+                var parentLi = $(this).closest('li');
+                var subUl = parentLi.children('ul');
+                if (subUl.length > 0) {
+                    subUl.slideToggle(150);
+                    $(this).toggleClass('glyphicon-chevron-right glyphicon-chevron-down');
+                }
+            });
+        }
+
+        /** 加载右侧列表 */
+        function loadRightList(nodeId, rootId) {
+            var url = '${ctx}/workKnowledgeBase/share/list?treeNodeId=' + nodeId + '&rootId=' + rootId;
+            $('#rightContent').attr('src', url);
+        }
+
+        /** 新增根节点 */
+        function addRootNode() {
+            openTreeDialog('新增知识库分类', '${ctx}/workKnowledgeBase/tree/form', '1000px', '800px');
+        }
+
+        /** 新增子节点 */
+        function addChildNode(parentId) {
+            openTreeDialog('新增子节点', '${ctx}/workKnowledgeBase/tree/form?parentId=' + parentId, '1000px', '500px');
+        }
+
+        /** 编辑节点 */
+        function editNode(nodeId) {
+            openTreeDialog('编辑节点', '${ctx}/workKnowledgeBase/tree/form?id=' + nodeId, '1000px', '500px');
+        }
+
+        /** 删除节点 */
+        function deleteNode(nodeId) {
+            layer.open({
+                title: '删除确认',
+                content: '确认要删除该节点及所有子节点吗?',
+                skin: 'two-btns',
+                btn: ['确定', '取消'],
+                btn1: function(index) {
+                    $.ajax({
+                        type: 'POST',
+                        url: '${ctx}/workKnowledgeBase/tree/delete?id=' + nodeId,
+                        success: function(data) {
+                            if (data.success) {
+                                layer.msg('删除成功', {icon: 1});
+                                layer.close(index);
+                                refreshTree();
+                            } else {
+                                layer.msg(data.message || '删除失败', {icon: 0});
+                            }
+                        }
+                    });
+                },
+                btn2: function(index) {
+                    layer.close(index);
+                }
+            });
+        }
+
+        /** 打开树节点弹窗 */
+        function openTreeDialog(title, url, width, height) {
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: title,
+                maxmin: true,
+                content: url,
+                skin: 'three-btns',
+                btn: ['提交', '关闭'],
+                btn1: function(index, layero) {
+                    var body = top.layer.getChildFrame('body', index);
+                    var iframeWin = layero.find('iframe')[0];
+                    var inputForm = body.find('#inputForm');
+                    inputForm.attr('target', top.getActiveTab().attr('name'));
+                    if (iframeWin.contentWindow.doSubmit(1)) {
+                        setTimeout(function() {
+                            top.layer.close(index);
+                            refreshTree();
+                        }, 300);
+                    }
+                },
+                btn2: function(index) {
+                    layer.close(index);
+                }
+            });
+        }
+
+        /** 刷新左侧树 */
+        function refreshTree() {
+            $.ajax({
+                url: '${ctx}/workKnowledgeBase/tree/treeData',
+                success: function(data) {
+                    renderTree(data);
+                    bindTreeClick();
+                }
+            });
+        }
+
+        /** 渲染树节点 */
+        function renderTree(data) {
+            var html = buildTreeHtml(data, '0');
+            $('#treeContainer').html(html);
+        }
+
+        /** 递归构建树HTML */
+        function buildTreeHtml(nodes, parentId) {
+            var html = '<ul class="nav nav-stacked">';
+            var hasChild = false;
+            for (var i = 0; i < nodes.length; i++) {
+                var node = nodes[i];
+                if (node.parentId === parentId) {
+                    hasChild = true;
+                    var hasChildren = hasChildNodes(nodes, node.id);
+                    html += '<li>';
+                    html += '<div class="tree-node-item" data-id="' + node.id + '" data-root-id="' + node.rootId + '">';
+                    if (hasChildren) {
+                        html += '<i class="glyphicon glyphicon-chevron-down tree-toggle" style="cursor:pointer;margin-right:3px;font-size:10px;"></i>';
+                    } else {
+                        html += '<i class="glyphicon glyphicon-file" style="margin-right:5px;color:#5b9bd5;"></i>';
+                    }
+                    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>';
+                    html += '</span>';
+                    html += '</div>';
+                    if (hasChildren) {
+                        html += buildTreeHtml(nodes, node.id);
+                    }
+                    html += '</li>';
+                }
+            }
+            html += '</ul>';
+            return hasChild ? html : '';
+        }
+
+        function hasChildNodes(nodes, parentId) {
+            for (var i = 0; i < nodes.length; i++) {
+                if (nodes[i].parentId === parentId) return true;
+            }
+            return false;
+        }
+
+        resizeLeftRightWindow = function() {
+            var height = $(window).height() - 60;
+            $('#leftPanel').css('min-height', height + 'px');
+            $('#rightContent').css('height', height + 'px');
+        };
+
+        $(window).resize(function() {
+            resizeLeftRightWindow();
+        });
+    </script>
+    <style>
+        body { background-color: transparent; }
+        .kb-layout { display: flex; width: 100%; min-height: calc(100vh - 60px); }
+        .kb-left {
+            width: 240px;
+            min-width: 200px;
+            background: #fff;
+            border-right: 1px solid #e5e5e5;
+            overflow-y: auto;
+            padding: 0;
+            flex-shrink: 0;
+        }
+        .kb-left .left-header {
+            background: #5b9bd5;
+            color: #fff;
+            padding: 10px 12px;
+            font-size: 13px;
+            font-weight: bold;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+        }
+        .kb-left .left-header .btn-add-root {
+            color: #fff;
+            border: 1px solid #fff;
+            border-radius: 3px;
+            padding: 1px 7px;
+            font-size: 12px;
+            cursor: pointer;
+            background: transparent;
+        }
+        .kb-left #treeContainer ul { list-style: none; padding: 0; margin: 0; }
+        .kb-left .tree-node-item {
+            padding: 7px 12px;
+            cursor: pointer;
+            font-size: 13px;
+            color: #333;
+            border-bottom: 1px solid #f0f0f0;
+            display: flex;
+            align-items: center;
+            transition: background .15s;
+        }
+        .kb-left .tree-node-item:hover { background: #edf4fc; }
+        .kb-left .tree-node-item.active { background: #d0e8ff; color: #1a6eb5; font-weight: bold; }
+        .kb-left .tree-node-item .tree-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+        .kb-left .tree-node-item .tree-ops { opacity: 0; transition: opacity .2s; margin-left: 4px; }
+        .kb-left .tree-node-item:hover .tree-ops { opacity: 1; }
+        .kb-left .tree-node-item .tree-ops a { color: #888; font-size: 12px; }
+        .kb-left .tree-node-item .tree-ops a:hover { color: #e94949; }
+        .kb-left li ul { padding-left: 16px; }
+        .kb-right { flex: 1; overflow: hidden; }
+        .kb-right iframe { width: 100%; border: none; display: block; }
+    </style>
+</head>
+<body>
+<div class="wrapper wrapper-content">
+    <sys:message content="${message}"/>
+    <div class="kb-layout">
+        <!-- 左侧树形菜单 -->
+        <div class="kb-left" id="leftPanel">
+            <div class="left-header">
+                <span><i class="glyphicon glyphicon-book" style="margin-right:5px;"></i>知识库分类</span>
+                <button class="btn-add-root" onclick="addRootNode()"><i class="glyphicon glyphicon-plus"></i> 新增分类</button>
+            </div>
+            <div id="treeContainer">
+                <script>
+                    // 后端渲染初始树数据
+                    var initTreeData = ${fns:toJson(treeList)};
+                    $(document).ready(function() {
+                        renderTree(initTreeData);
+                        bindTreeClick();
+                    });
+                </script>
+            </div>
+        </div>
+        <!-- 右侧内容区(iframe) -->
+        <div class="kb-right">
+            <iframe id="rightContent" src="about:blank" scrolling="auto"></iframe>
+        </div>
+    </div>
+</div>
+<script>
+    $(document).ready(function() {
+        resizeLeftRightWindow();
+    });
+</script>
+</body>
+</html>

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

@@ -0,0 +1,154 @@
+<%@ 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()) {
+                // 提交前收集动态字段值为JSON
+                collectDynamicValues();
+                $('#inputForm').submit();
+                return true;
+            }
+            return false;
+        }
+
+        $(document).ready(function() {
+            validateForm = $('#inputForm').validate({
+                submitHandler: function(form) {
+                    loading('正在提交,请稍等...');
+                    form.submit();
+                },
+                errorContainer: '#messageBox',
+                errorPlacement: function(error, element) {
+                    $('#messageBox').text('输入有误,请先更正。');
+                    error.insertAfter(element);
+                }
+            });
+        });
+
+        /** 收集动态字段值为JSON数组,写入隐藏域 */
+        function collectDynamicValues() {
+            var values = [];
+            $('.dynamic-field-input').each(function() {
+                var fieldId = $(this).data('field-id');
+                var fieldKey = $(this).data('field-key');
+                var val = $(this).val();
+                values.push({dynamicFieldId: fieldId, fieldKey: fieldKey, fieldValue: val || ''});
+            });
+            $('#dynamicValuesJson').val(JSON.stringify(values));
+        }
+
+        /** 文件上传回调:attachmentManager 选择文件后触发上传 */
+        function insertTitle(tValue) {
+            var files = $('#attachment_file_knowledgeFile')[0].files;
+            for (var i = 0; i < files.length; i++) {
+                var file = files[i];
+                var attachmentId = '';
+                var attachmentFlag = '6';
+                var storeAs = 'workKnowledgeBaseShareInfo';
+                var uploadPath = 'http://gangwan-app.oss-cn-hangzhou.aliyuncs.com/' + storeAs;
+                var divId = '_attachment';
+                $('#addFile' + divId).show();
+                multipartUploadWithSts(storeAs, file, attachmentId, attachmentFlag, uploadPath, divId, 0);
+            }
+        }
+    </script>
+</head>
+<body>
+<div class="single-form">
+    <div class="container">
+        <sys:message content="${message}"/>
+        <form:form id="inputForm" modelAttribute="entity"
+                   action="${ctx}/workKnowledgeBase/share/save" method="post"
+                   class="form-horizontal layui-form">
+            <form:hidden path="id"/>
+            <form:hidden path="treeNodeId"/>
+            <form:hidden path="rootId"/>
+            <!-- 动态字段值JSON隐藏域 -->
+            <input type="hidden" id="dynamicValuesJson" name="dynamicValuesJson"/>
+
+            <div class="form-group layui-row">
+                <div class="form-group-label"><h2>知识库文件信息</h2></div>
+
+                <!-- 文件名(必填) -->
+                <div class="layui-item layui-col-sm6 lw6">
+                    <label class="layui-form-label"><span class="require-item">*</span>文件名:</label>
+                    <div class="layui-input-block">
+                        <form:input path="fileName" placeholder="请输入文件名称" htmlEscape="false"
+                                    maxlength="200" class="form-control layui-input required"/>
+                    </div>
+                </div>
+
+                <!-- 备注 -->
+                <div class="layui-item layui-col-sm6 lw6">
+                    <label class="layui-form-label">备注:</label>
+                    <div class="layui-input-block">
+                        <form:textarea path="remarks" placeholder="备注信息" rows="2"
+                                       class="form-control layui-input"/>
+                    </div>
+                </div>
+            </div>
+
+            <!-- 文件上传区域(阿里云通用附件组件) -->
+            <table:attachmentManager
+                    title="附件上传"
+                    addBtnText="上传文件"
+                    baseId="knowledgeFile"
+                    attachments="${entity.attachments}"
+                    fileHandlerFuncName="insertTitle"
+                    attachmentFlag="199"
+                    storeAs="workKnowledgeBaseShareInfo"
+            />
+
+            <!-- 动态扩展字段(与主表单整合,流式排列) -->
+            <c:if test="${not empty dynamicFields}">
+                <div class="form-group layui-row">
+                    <c:forEach items="${dynamicFields}" var="field">
+                        <div class="layui-item layui-col-sm6 lw6">
+                            <label class="layui-form-label">${field.fieldLabel}:</label>
+                            <div class="layui-input-block">
+                                <c:choose>
+                                    <c:when test="${field.fieldType == 'Integer'}">
+                                        <input type="text"
+                                               class="form-control layui-input dynamic-field-input digits"
+                                               data-field-id="${field.id}"
+                                               data-field-key="${field.fieldKey}"
+                                               placeholder="请输入整数"
+                                               value="${dynValues[field.id]}"/>
+                                    </c:when>
+                                    <c:when test="${field.fieldType == 'Double'}">
+                                        <input type="text"
+                                               class="form-control layui-input dynamic-field-input number"
+                                               data-field-id="${field.id}"
+                                               data-field-key="${field.fieldKey}"
+                                               placeholder="请输入小数"
+                                               value="${dynValues[field.id]}"/>
+                                    </c:when>
+                                    <c:otherwise>
+                                        <input type="text"
+                                               class="form-control layui-input dynamic-field-input"
+                                               data-field-id="${field.id}"
+                                               data-field-key="${field.fieldKey}"
+                                               placeholder="请输入${field.fieldLabel}"
+                                               value="${dynValues[field.id]}"/>
+                                    </c:otherwise>
+                                </c:choose>
+                            </div>
+                        </div>
+                    </c:forEach>
+                </div>
+            </c:if>
+
+            <div class="form-group layui-row page-end"></div>
+        </form:form>
+    </div>
+</div>
+</body>
+</html>

+ 242 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareList.jsp

@@ -0,0 +1,242 @@
+<%@ 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}/layer-v2.3/layui/layui.all.js" charset="utf-8"></script>
+    <script type="text/javascript">
+        var currentTreeNodeId = '${treeNodeId}';
+        var currentRootId = '${rootId}';
+
+        $(document).ready(function() {
+            // do nothing, layui table rendered below
+        });
+
+        function openDialog(title, url, width, height, target) {
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {
+                width = 'auto'; height = 'auto';
+            }
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: title,
+                maxmin: true,
+                content: url,
+                skin: 'three-btns',
+                btn: ['提交', '关闭'],
+                btn1: function(index, layero) {
+                    var body = top.layer.getChildFrame('body', index);
+                    var iframeWin = layero.find('iframe')[0];
+                    var inputForm = body.find('#inputForm');
+                    var top_iframe = top.getActiveTab().attr('name');
+                    inputForm.attr('target', top_iframe);
+                    if (iframeWin.contentWindow.doSubmit(1)) {
+                        setTimeout(function() { top.layer.close(index); }, 100);
+                    }
+                },
+                btn2: function(index) { layer.close(index); }
+            });
+        }
+
+        /** 删除文件 */
+        function deleteShare(id) {
+            layer.open({
+                title: '删除确认',
+                content: '确认要删除该文件记录吗?',
+                skin: 'two-btns',
+                btn: ['确定', '取消'],
+                btn1: function(index) {
+                    $.ajax({
+                        type: 'POST',
+                        url: '${ctx}/workKnowledgeBase/share/delete?id=' + id,
+                        success: function(data) {
+                            if (data.success) {
+                                layer.msg('删除成功', {icon: 1});
+                                layer.close(index);
+                                search();
+                            } else {
+                                layer.msg(data.message || '删除失败', {icon: 0});
+                            }
+                        }
+                    });
+                },
+                btn2: function(index) { layer.close(index); }
+            });
+        }
+
+        /** 查询 */
+        function search() {
+            $('#searchForm').submit();
+        }
+
+        /** 重置查询 */
+        function resetSearch() {
+            // 清空所有查询输入
+            $('#searchForm input[type=text]').val('');
+            $('#searchForm input[type=search]').val('');
+            $('#searchForm').submit();
+        }
+
+        resizeListWindow1 = function() {
+            var height = $(window).height() - 10;
+            $('body').css('min-height', height + 'px');
+        };
+        $(window).resize(function() { resizeListWindow1(); });
+    </script>
+    <style>
+        body { background-color: transparent; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#26FFFFFF, endColorstr=#26FFFFFF); background-color: rgba(255,255,255,0); }
+    </style>
+</head>
+<body>
+<div class="wrapper wrapper-content">
+    <sys:message content="${message}"/>
+    <div class="layui-row">
+        <!-- 查询条件区域 -->
+        <div class="full-width fl">
+            <div class="contentShadow layui-row" id="queryDiv">
+                <form id="searchForm" action="${ctx}/workKnowledgeBase/share/list" method="post" class="form-inline">
+                    <input type="hidden" name="treeNodeId" value="${treeNodeId}"/>
+                    <input type="hidden" name="rootId" value="${rootId}"/>
+                    <input id="pageNo" name="pageNo" type="hidden" value="${page.pageNo}"/>
+                    <input id="pageSize" name="pageSize" type="hidden" value="${page.pageSize}"/>
+                    <div class="commonQuery">
+                        <%-- 固定查询:文件名 --%>
+                        <div class="layui-item query athird">
+                            <label class="layui-form-label">文件名:</label>
+                            <div class="layui-input-block with-icon">
+                                <input type="text" name="fileName" value="${shareInfo.fileName}"
+                                       placeholder="文件名模糊查询" class="form-control layui-input"/>
+                            </div>
+                        </div>
+                        <%-- 动态查询项:根据表3配置自动生成 --%>
+                        <c:forEach items="${dynamicFields}" var="field">
+                            <div class="layui-item query athird">
+                                <label class="layui-form-label">${field.fieldLabel}:</label>
+                                <div class="layui-input-block with-icon">
+                                    <input type="text" name="dynamic_${field.id}"
+                                           value="${dynamicConditions[field.id]}"
+                                           placeholder="${field.fieldLabel}查询"
+                                           class="form-control layui-input"/>
+                                </div>
+                            </div>
+                        </c:forEach>
+                        <div class="layui-item athird">
+                            <div class="input-group">
+                                <div class="layui-btn-group search-spacing">
+                                    <button type="button" class="layui-btn layui-btn-sm layui-bg-blue" onclick="search()">查询</button>
+                                    <button type="button" class="layui-btn layui-btn-sm" onclick="resetSearch()">重置</button>
+                                </div>
+                            </div>
+                        </div>
+                        <div style="clear:both;"></div>
+                    </div>
+                </form>
+            </div>
+        </div>
+
+        <!-- 工具栏 + 表格 -->
+        <div class="full-width fl">
+            <div class="contentShadow layui-form contentDetails">
+                <div class="nav-btns">
+                    <div class="layui-btn-group">
+                        <c:if test="${not empty treeNodeId}">
+                            <shiro:hasPermission name="workKnowledgeBase:share:add">
+                                <button class="layui-btn layui-btn-sm layui-bg-blue"
+                                        onclick="openDialog('新增文件','${ctx}/workKnowledgeBase/share/form?treeNodeId=${treeNodeId}&rootId=${rootId}','80%','80%')">
+                                    <i class="glyphicon glyphicon-plus"></i> 新增
+                                </button>
+                            </shiro:hasPermission>
+                        </c:if>
+                        <button class="layui-btn layui-btn-sm" onclick="search()" title="刷新">刷新</button>
+                    </div>
+                    <div style="clear:both;"></div>
+                </div>
+
+                <%-- 当未选择节点时提示 --%>
+                <c:if test="${empty treeNodeId or empty rootId}">
+                    <div style="text-align:center;padding:60px;color:#999;font-size:14px;">
+                        <i class="glyphicon glyphicon-arrow-left" style="font-size:20px;"></i>
+                        &nbsp;请先在左侧选择知识库节点
+                    </div>
+                </c:if>
+
+                <c:if test="${not empty treeNodeId and not empty rootId}">
+                    <%-- 动态表格(使用Layui table渲染) --%>
+                    <table class="oa-table layui-table" id="contentTable"></table>
+
+                    <!-- 分页代码 -->
+                    <table:page page="${page}"></table:page>
+                    <div style="clear:both;"></div>
+                </c:if>
+            </div>
+        </div>
+    </div>
+</div>
+
+<c:if test="${not empty treeNodeId and not empty rootId}">
+<script src="${ctxStatic}/layer-v2.3/layui/layui.all.js" charset="utf-8"></script>
+<script>
+    layui.use('table', function() {
+        // 构建动态列配置
+        var cols = [
+            {field: 'index', align: 'center', width: 50, title: '序号'},
+            {field: 'fileName', align: 'center', title: '文件名', minWidth: 150},
+            {field: 'fileUrl', align: 'center', title: '文件地址', minWidth: 200, templet: function(d) {
+                if (d.fileUrl && d.fileUrl !== '') {
+                    return '<a href="' + d.fileUrl + '" target="_blank" title="' + d.fileUrl + '">' +
+                           '<i class="glyphicon glyphicon-paperclip"></i> 查看文件</a>';
+                }
+                return '-';
+            }},
+            <c:forEach items="${dynamicFields}" var="field">
+            {field: 'dynamic_${field.fieldKey}', align: 'center', title: '${field.fieldLabel}', minWidth: 100},
+            </c:forEach>
+            {field: 'createTime', align: 'center', title: '创建时间', width: 160},
+            {align: 'center', title: '操作', width: 160, fixed: 'right', templet: function(d) {
+                var xml = '<div class="layui-btn-group">';
+                xml += '<a href="javascript:void(0)" onclick="openDialog(\'编辑文件\',\'${ctx}/workKnowledgeBase/share/form?id=' + d.id + '&treeNodeId=${treeNodeId}&rootId=${rootId}\',\'80%\',\'80%\')" class="layui-btn layui-btn-xs layui-bg-green"> 修改</a>';
+                xml += '<a href="javascript:void(0)" onclick="deleteShare(\'' + d.id + '\')" class="layui-btn layui-btn-xs layui-bg-red"> 删除</a>';
+                xml += '</div>';
+                return xml;
+            }}
+        ];
+
+        layui.table.render({
+            limit: ${page.pageSize},
+            id: 'checkboxTable',
+            elem: '#contentTable',
+            page: false,
+            cols: [cols],
+            data: [
+                <c:choose>
+                <c:when test="${not empty page.list}">
+                <c:forEach items="${page.list}" var="row" varStatus="status">
+                <c:if test="${status.index != 0}">,</c:if>
+                {
+                    "index": "${status.index + 1}"
+                    ,"id": "${row.id}"
+                    ,"fileName": "<c:out value='${row.fileName}'/>"
+                    ,"fileUrl": "<c:out value='${row.fileUrl}'/>"
+                    ,"createTime": "${row.createTime}"
+                    <c:forEach items="${dynamicFields}" var="field">
+                    ,"dynamic_${field.fieldKey}": "<c:out value='${row["dynamic_".concat(field.fieldKey)]}'/>"
+                    </c:forEach>
+                }
+                </c:forEach>
+                </c:when>
+                <c:otherwise></c:otherwise>
+                </c:choose>
+            ]
+        });
+    });
+
+    resizeListTable();
+    resizeListWindow1();
+    $(window).resize(function() {
+        resizeListWindow1();
+    });
+</script>
+</c:if>
+</body>
+</html>

+ 214 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseTreeForm.jsp

@@ -0,0 +1,214 @@
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@ include file="/webpage/include/taglib.jsp"%>
+<html>
+<head>
+    <title>知识库节点管理</title>
+    <meta name="decorator" content="default"/>
+    <!-- 先加载jQuery(必须在layui之前!)-->
+    <script type="text/javascript" src="${ctxStatic}/jquery/jquery-1.10.2.min.js"></script>
+    <!-- Layui 核心 -->
+    <link rel="stylesheet" type="text/css" href="${ctxStatic}/layui/css/layui.css"/>
+    <script type="text/javascript" src="${ctxStatic}/layui/layui.js"></script>
+
+    <script type="text/javascript">
+        var validateForm;
+        var rowIndex = 0;
+
+        // 提交
+        function doSubmit(i) {
+            if (validateForm.form()) {
+                collectDynamicFields();
+                $('#inputForm').submit();
+                return true;
+            }
+            return false;
+        }
+
+        $(document).ready(function() {
+            // 表单验证
+            validateForm = $('#inputForm').validate({
+                submitHandler: function(form) {
+                    loading('正在提交,请稍等...');
+                    form.submit();
+                },
+                errorContainer: '#messageBox',
+                errorPlacement: function(error, element) {
+                    $('#messageBox').text('输入有误,请先更正。');
+                    error.insertAfter(element);
+                }
+            });
+
+            // 初始化 Layui 表单渲染(关键修复!)
+            layui.use('form', function(){
+                var form = layui.form;
+                form.render(); // 渲染所有表单元素
+            });
+
+            // 初始化已有动态字段
+            <c:if test="${not empty workKnowledgeBaseTreeInfo.dynamicFields}">
+            <c:forEach items="${workKnowledgeBaseTreeInfo.dynamicFields}" var="field" varStatus="idx">
+            addDynamicRow('${field.id}', '${field.fieldKey}', '${field.fieldLabel}', '${field.fieldType}', '${field.sort}');
+            </c:forEach>
+            </c:if>
+        });
+
+        // 新增动态行
+        function addDynamicRow(id, fieldKey, fieldLabel, fieldType, sort) {
+            id = id || '';
+            fieldKey = fieldKey || '';
+            fieldLabel = fieldLabel || '';
+            fieldType = fieldType || 'String';
+            sort = sort || '';
+            rowIndex++;
+            var idx = rowIndex;
+
+            var selectedString = (fieldType === 'String') ? 'selected' : '';
+            var selectedInteger = (fieldType === 'Integer') ? 'selected' : '';
+            var selectedDouble = (fieldType === 'Double') ? 'selected' : '';
+
+            var tr = '<tr id="dynRow_' + idx + '">'
+                + '<td><input type="hidden" name="dynId_' + idx + '" value="' + id + '"/>'
+                + '<input type="text" name="dynFieldKey_' + idx + '" value="' + fieldKey + '" placeholder="英文标识" class="layui-input" style="width:100%;"/></td>'
+                + '<td><input type="text" name="dynFieldLabel_' + idx + '" value="' + fieldLabel + '" placeholder="字段名称" class="layui-input" style="width:100%;"/></td>'
+                + '<td><select name="dynFieldType_' + idx + '" class="layui-select" style="width:100%;">'
+                + '<option value="String" ' + selectedString + '>String</option>'
+                + '<option value="Integer" ' + selectedInteger + '>Integer</option>'
+                + '<option value="Double" ' + selectedDouble + '>Double</option>'
+                + '</select></td>'
+                + '<td><input type="number" name="dynSort_' + idx + '" value="' + sort + '" placeholder="排序" class="layui-input" style="width:100%;"/></td>'
+                + '<td><a href="javascript:void(0)" onclick="removeDynRow(' + idx + ')" class="layui-btn layui-btn-xs layui-btn-danger">删除</a></td>'
+                + '</tr>';
+
+            $('#dynFieldTableBody').append(tr);
+
+            // 动态添加后重新渲染 Layui 下拉框
+            layui.use('form', function(){
+                layui.form.render('select');
+            });
+        }
+
+        // 删除行
+        function removeDynRow(idx) {
+            $('#dynRow_' + idx).remove();
+        }
+
+        // 收集JSON
+        function collectDynamicFields() {
+            var fields = [];
+            $('#dynFieldTableBody tr').each(function() {
+                var id = $(this).find('input[name^="dynId_"]').val();
+                var fieldKey = $(this).find('input[name^="dynFieldKey_"]').val();
+                var fieldLabel = $(this).find('input[name^="dynFieldLabel_"]').val();
+                var fieldType = $(this).find('select[name^="dynFieldType_"]').val();
+                var sort = $(this).find('input[name^="dynSort_"]').val();
+                if (fieldKey || fieldLabel) {
+                    fields.push({id: id, fieldKey: fieldKey, fieldLabel: fieldLabel, fieldType: fieldType, sort: sort || 0});
+                }
+            });
+            $('#dynamicFieldsJson').val(JSON.stringify(fields));
+        }
+    </script>
+</head>
+<body>
+<div class="single-form">
+    <div class="container">
+        <sys:message content="${message}"/>
+
+        <form:form id="inputForm" modelAttribute="workKnowledgeBaseTreeInfo"
+                   action="${ctx}/workKnowledgeBase/tree/save" method="post"
+                   class="layui-form">
+
+            <form:hidden path="id"/>
+            <form:hidden path="parentId"/>
+            <form:hidden path="rootId"/>
+            <input type="hidden" id="dynamicFieldsJson" name="dynamicFieldsJson"/>
+
+            <!-- 基本信息 -->
+            <div class="layui-form-item">
+                <div class="layui-inline" style="width:100%; margin-top:15px;">
+                    <h2>知识库节点信息</h2>
+                </div>
+
+                <!-- 上级节点 -->
+                <c:if test="${not empty workKnowledgeBaseTreeInfo.parentId and workKnowledgeBaseTreeInfo.parentId != '0'}">
+                    <div class="layui-form-item">
+                        <label class="layui-form-label">上级节点:</label>
+                        <div class="layui-input-block">
+                            <input type="text" value="${parentName}" readonly class="layui-input" style="background:#f5f5f5;">
+                        </div>
+                    </div>
+                </c:if>
+
+                <!-- 节点名称 -->
+                <div class="layui-form-item">
+                    <label class="layui-form-label"><span class="require-item">*</span>节点名称:</label>
+                    <div class="layui-input-block">
+                        <form:input path="treeName" placeholder="请输入节点名称" maxlength="100" class="layui-input required"/>
+                    </div>
+                </div>
+
+                <!-- 排序 -->
+                <div class="layui-form-item">
+                    <label class="layui-form-label">排序:</label>
+                    <div class="layui-input-block">
+                        <form:input path="sort" placeholder="请输入排序数字" class="layui-input digits"/>
+                    </div>
+                </div>
+
+                <!-- 备注 -->
+                <div class="layui-form-item">
+                    <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>
+
+            <!-- 动态字段(仅根节点显示) -->
+            <c:if test="${empty workKnowledgeBaseTreeInfo.parentId or workKnowledgeBaseTreeInfo.parentId == '0'}">
+                <div class="layui-form-item">
+                    <div class="layui-inline" style="width:100%; margin-top:20px;">
+                        <h2>动态字段配置
+                            <button type="button" class="layui-btn layui-btn-sm layui-btn-normal" onclick="addDynamicRow()">
+                                <i class="layui-icon layui-icon-add-1"></i> 新增字段
+                            </button>
+                        </h2>
+                    </div>
+
+                    <table class="layui-table" lay-size="sm" style="width:100%;">
+                        <thead>
+                        <tr>
+                            <th>字段标识(英文)</th>
+                            <th>字段名称(中文)</th>
+                            <th>字段类型</th>
+                            <th>排序</th>
+                            <th>操作</th>
+                        </tr>
+                        </thead>
+                        <tbody id="dynFieldTableBody"></tbody>
+                    </table>
+
+                    <div style="font-size:12px; color:#666; margin-top:5px;">
+                        <i class="layui-icon layui-icon-help"></i>
+                        字段标识请使用英文字母/数字,类型:String=文本,Integer=整数,Double=小数
+                    </div>
+                </div>
+            </c:if>
+
+        </form:form>
+    </div>
+</div>
+
+<script>
+    // 提交前收集动态字段
+    var _origDoSubmit = doSubmit;
+    doSubmit = function(i) {
+        var parentIdVal = '${workKnowledgeBaseTreeInfo.parentId}';
+        if (parentIdVal === '' || parentIdVal === '0') {
+            collectDynamicFields();
+        }
+        return _origDoSubmit(i);
+    };
+</script>
+</body>
+</html>

+ 4 - 1
src/main/webapp/webpage/modules/projectPerformanceDatabase/projectPerformanceList.jsp

@@ -958,9 +958,12 @@
 				<div class="nav-btns">
 					<%--此处按钮样式包括 nav-btn-add nav-btn-refresh nav-btn-import nav-btn-export nav-btn-query nav-btn-reset--%>
 
-						<shiro:hasPermission name="ruralProject:ruralProjectMessageAll:reportBatchReject">
+						<shiro:hasPermission name="projectPerformance:add">
 							<button type="button" data-toggle="tooltip" data-placement="top" class="layui-btn layui-btn-sm layui-bg-blue" id="reportBatchReject"> 批量设置业绩库</button>
 						</shiro:hasPermission>
+						<shiro:hasPermission name="projectPerformance:export">
+							<table:exportExcel url="${ctx}/projectPerformance/export"></table:exportExcel><!-- 导出按钮 -->
+						</shiro:hasPermission>
 					<div class="layui-btn-group">
 						<button class="layui-btn layui-btn-sm" data-toggle="tooltip" data-placement="left" onclick="sortOrRefresh()" title="刷新"> 刷新</button>
 					</div>

+ 1 - 1
src/main/webapp/webpage/modules/sys/sysLogin.jsp

@@ -18,7 +18,7 @@
 	<link href="${ctxStatic}/awesome/4.4/css/font-awesome.min.css" rel="stylesheet" />
 	<!-- jeeplus -->
 	<link href="${ctxStatic}/common/jeeplus.css" type="text/css" rel="stylesheet" />
-	<script src="${ctxStatic}/common/jeeplus.js?26" type="text/javascript"></script>
+	<script src="${ctxStatic}/common/jeeplus.js?27" type="text/javascript"></script>
 	<link rel="shortcut icon" href="images/favicon.png" type="image/png">
 	<!-- text fonts -->
 	<link rel="stylesheet" href="${ctxStatic }/common/login/ace-fonts.css" />

+ 1 - 1
src/main/webapp/webpage/modules/sys/sysLogin2.jsp

@@ -16,7 +16,7 @@
 		<link href="${ctxStatic}/awesome/4.4/css/font-awesome.min.css" rel="stylesheet" />
 		<!-- jeeplus -->
 		<link href="${ctxStatic}/common/jeeplus.css" type="text/css" rel="stylesheet" />
-		<script src="${ctxStatic}/common/jeeplus.js?26" type="text/javascript"></script>
+		<script src="${ctxStatic}/common/jeeplus.js?27" type="text/javascript"></script>
 		<link rel="shortcut icon" href="images/favicon.png" type="image/png">
 		<!-- text fonts -->
 		<link rel="stylesheet" href="${ctxStatic }/common/login/ace-fonts.css" />

+ 1 - 1
src/main/webapp/webpage/modules/workcontractinfo/newWorkContract/workContractInfoFormAdd.jsp

@@ -748,7 +748,7 @@
 								<label class="layui-form-label">项目负责人:</label>
 								<div class="layui-input-block  with-icon">
 									<sys:treeselect id="master" name="projectLeaderIds" value="${workContractInfo.projectLeaderIds}" labelName="leaderNameStr" labelValue="${workContractInfo.leaderNameStr}"
-													cssStyle="background-color: #fff" title="用户" url="/sys/office/treeDataAll?type=3" cssClass="form-control judgment layui-input" allowClear="true" notAllowSelectParent="true"/>
+													cssStyle="background-color: #fff" title="用户" url="/sys/office/treeDataAll?type=3" cssClass="form-control layui-input" allowClear="true" notAllowSelectParent="true"/>
 								</div>
 							</div>
 

+ 10 - 4
src/main/webapp/webpage/modules/workcontractinfo/workContractInfoList.jsp

@@ -736,12 +736,18 @@
                             var xml = "<span style=\"cursor:default;\" class=\"status-label status-label-" + st.label + "\" >" + st.status + "</span>";
                         return xml;
                     }}
-                ,{align:'center', title: '归档状态',  width:70,templet:function(d){
+                ,{align:'center', title: '归档状态',  width:95,templet:function(d){
                         var st = getRuralProjectArchiveState(d.contrractRecordStatus);
-                        if(st.action)
+                        if(st.action){
 							var xml = "<span onclick=\"openDialogView('流程追踪', '${ctx}/workcontractrecord/workContractRecord/getProcessOne?id=" + d.contrractRecordId + "','95%','95%')\" class=\"status-label status-label-" + st.label + "\" >" + st.status + "</span>";
-                        else
-                            var xml = "<span style=\"cursor:default;\" class=\"status-label status-label-" + st.label + "\" >" + st.status + "</span>";
+						}
+                        else{
+							if('15' === d.contrractRecordStatus){
+								var xml = "<span style=\"cursor:default;\" class=\"new-status-label status-label-" + st.label + "\" >" + st.status + "</span>";
+							}else{
+								var xml = "<span style=\"cursor:default;\" class=\"status-label status-label-" + st.label + "\" >" + st.status + "</span>";
+							}
+						}
                         return xml;
                     }}
                 ,{align:'center', title: '借用状态',  width:70,templet:function(d){

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceAllForm.jsp

@@ -1319,7 +1319,7 @@
 						<input type="radio" name="redFlushReason" lay-filter="redFlushReasonRadio" title="销售折让" value="04">
 					</div>
 				</div>
-				<div class="layui-item layui-col-sm12 with-textarea situationDetail">
+				<div class="layui-item layui-col-sm12 with-textarea redFlushReason">
 					<label class="layui-form-label double-line"><span class="require-item">*</span>红冲情况说明:</label>
 					<div class="layui-input-block">
 						<form:textarea path="situationDetail" placeholder="请输入情况说明" htmlEscape="false" rows="4" class="form-control judgment "/>

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceAllModify.jsp

@@ -1247,7 +1247,7 @@
 						<input type="radio" name="redFlushReason" lay-filter="redFlushReasonRadio" title="销售折让" value="04">
 					</div>
 				</div>
-				<div class="layui-item layui-col-sm12 with-textarea situationDetail">
+				<div class="layui-item layui-col-sm12 with-textarea redFlushReason">
 					<label class="layui-form-label double-line"><span class="require-item">*</span>红冲情况说明:</label>
 					<div class="layui-input-block">
 						<form:textarea path="situationDetail" placeholder="请输入情况说明" htmlEscape="false" rows="4" class="form-control judgment "/>

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceAllRcForm.jsp

@@ -1315,7 +1315,7 @@
 						<input type="radio" name="redFlushReason" lay-filter="redFlushReasonRadio" title="销售折让" value="04">
 					</div>
 				</div>
-				<div class="layui-item layui-col-sm12 with-textarea situationDetail">
+				<div class="layui-item layui-col-sm12 with-textarea redFlushReason">
 					<label class="layui-form-label double-line"><span class="require-item">*</span>红冲情况说明:</label>
 					<div class="layui-input-block">
 						<form:textarea path="situationDetail" placeholder="请输入情况说明" htmlEscape="false" rows="4" class="form-control judgment "/>

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceAllTwoForm.jsp

@@ -1358,7 +1358,7 @@
 						<input type="radio" name="redFlushReason" lay-filter="redFlushReasonRadio" title="销售折让" value="04">
 					</div>
 				</div>
-				<div class="layui-item layui-col-sm12 with-textarea situationDetail">
+				<div class="layui-item layui-col-sm12 with-textarea redFlushReason">
 					<label class="layui-form-label double-line"><span class="require-item">*</span>红冲情况说明:</label>
 					<div class="layui-input-block">
 						<form:textarea path="situationDetail" placeholder="请输入情况说明" htmlEscape="false" rows="4" class="form-control judgment "/>

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceAllTwoRcForm.jsp

@@ -1314,7 +1314,7 @@
 						<input type="radio" name="redFlushReason" lay-filter="redFlushReasonRadio" title="销售折让" value="04">
 					</div>
 				</div>
-				<div class="layui-item layui-col-sm12 with-textarea situationDetail">
+				<div class="layui-item layui-col-sm12 with-textarea redFlushReason">
 					<label class="layui-form-label double-line"><span class="require-item">*</span>红冲情况说明:</label>
 					<div class="layui-input-block">
 						<form:textarea path="situationDetail" placeholder="请输入情况说明" htmlEscape="false" rows="4" class="form-control judgment "/>

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceModify.jsp

@@ -1322,7 +1322,7 @@
 						<input type="radio" name="redFlushReason" lay-filter="redFlushReasonRadio" title="销售折让" value="04">
 					</div>
 				</div>
-				<div class="layui-item layui-col-sm12 with-textarea situationDetail">
+				<div class="layui-item layui-col-sm12 with-textarea redFlushReason">
 					<label class="layui-form-label double-line"><span class="require-item">*</span>红冲情况说明:</label>
 					<div class="layui-input-block">
 						<form:textarea path="situationDetail" placeholder="请输入情况说明" htmlEscape="false" rows="4" class="form-control judgment"/>

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceNotProjectModify.jsp

@@ -1308,7 +1308,7 @@
 						<input type="radio" name="redFlushReason" lay-filter="redFlushReasonRadio" title="销售折让" value="04">
 					</div>
 				</div>
-				<div class="layui-item layui-col-sm12 with-textarea situationDetail">
+				<div class="layui-item layui-col-sm12 with-textarea redFlushReason">
 					<label class="layui-form-label double-line"><span class="require-item">*</span>红冲情况说明:</label>
 					<div class="layui-input-block">
 						<form:textarea path="situationDetail" placeholder="请输入情况说明" htmlEscape="false" rows="4" class="form-control judgment "/>

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceTwoForm.jsp

@@ -1417,7 +1417,7 @@
 						<input type="radio" name="redFlushReason" lay-filter="redFlushReasonRadio" title="销售折让" value="04">
 					</div>
 				</div>
-				<div class="layui-item layui-col-sm12 with-textarea situationDetail">
+				<div class="layui-item layui-col-sm12 with-textarea redFlushReason">
 					<label class="layui-form-label double-line"><span class="require-item">*</span>红冲情况说明:</label>
 					<div class="layui-input-block">
 						<form:textarea path="situationDetail" placeholder="请输入情况说明" htmlEscape="false" rows="4" class="form-control judgment"/>

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceTwoModify.jsp

@@ -1266,7 +1266,7 @@
 						<input type="radio" name="redFlushReason" lay-filter="redFlushReasonRadio" title="销售折让" value="04">
 					</div>
 				</div>
-				<div class="layui-item layui-col-sm12 with-textarea situationDetail">
+				<div class="layui-item layui-col-sm12 with-textarea redFlushReason">
 					<label class="layui-form-label double-line"><span class="require-item">*</span>红冲情况说明:</label>
 					<div class="layui-input-block">
 						<form:textarea path="situationDetail" placeholder="请输入情况说明" htmlEscape="false" rows="4" class="form-control judgment"/>

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceView.jsp

@@ -294,7 +294,7 @@
 						<input type="radio" name="redFlushReason" disabled lay-filter="redFlushReasonRadio" title="销售折让" value="04">
 					</div>
 				</div>
-				<div class="layui-item layui-col-sm12 with-textarea situationDetail">
+				<div class="layui-item layui-col-sm12 with-textarea redFlushReason">
 					<label class="layui-form-label double-line"><span class="require-item">*</span>红冲情况说明:</label>
 					<div class="layui-input-block">
 						<form:textarea path="situationDetail" readonly="true" placeholder="请输入情况说明" htmlEscape="false"  style="background-color: #f1f1f1"   rows="4" class="form-control judgment "/>