Bläddra i källkod

知识库内容调整

徐滕 2 veckor sedan
förälder
incheckning
baf5c49e5a
30 ändrade filer med 3298 tillägg och 34 borttagningar
  1. 68 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseAuditRecordDao.java
  2. 31 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBasePointDetailDao.java
  3. 29 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBasePointRuleDao.java
  4. 5 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseShareInfoDao.java
  5. 103 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/UserPointDetail.java
  6. 81 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/UserPointSummary.java
  7. 81 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseAuditRecord.java
  8. 56 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBasePointDetail.java
  9. 77 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBasePointQuery.java
  10. 55 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBasePointRule.java
  11. 55 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseShareInfo.java
  12. 64 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseAuditRecordService.java
  13. 108 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBasePointDetailService.java
  14. 104 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBasePointRuleService.java
  15. 366 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseShareService.java
  16. 117 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBasePointController.java
  17. 112 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBasePointRuleController.java
  18. 151 0
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseShareController.java
  19. 185 0
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseAuditRecordDao.xml
  20. 206 0
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBasePointDetailDao.xml
  21. 150 0
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBasePointRuleDao.xml
  22. 56 27
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseShareInfoDao.xml
  23. 2 1
      src/main/webapp/WEB-INF/tags/table/singleAttachmentManager.tag
  24. 21 0
      src/main/webapp/static/common/jeeplus.js
  25. 86 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBasePointRuleForm.jsp
  26. 241 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBasePointRuleList.jsp
  27. 168 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBasePointUserDetail.jsp
  28. 145 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBasePointUserList.jsp
  29. 147 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareDetail.jsp
  30. 228 6
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareList.jsp

+ 68 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseAuditRecordDao.java

@@ -0,0 +1,68 @@
+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.WorkKnowledgeBaseAuditRecord;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 知识库审核记录 DAO
+ * @author: 徐滕
+ * @version: 2026-05-18
+ */
+@MyBatisDao
+public interface WorkKnowledgeBaseAuditRecordDao extends CrudDao<WorkKnowledgeBaseAuditRecord> {
+
+    /**
+     * 根据文件ID查询审核记录列表(按审核时间倒序)
+     */
+    List<WorkKnowledgeBaseAuditRecord> findByFileId(String fileId);
+
+    /**
+     * 根据文件ID查询本轮审核记录(audit_time >= startTime)
+     */
+    List<WorkKnowledgeBaseAuditRecord> findByFileIdSinceTime(@Param("fileId") String fileId, @Param("startTime") Date startTime);
+
+    /**
+     * 检查某用户是否已审核过某文件(防止重复审核)
+     */
+    int countByFileIdAndUserId(@Param("fileId") String fileId, @Param("auditUserId") String auditUserId);
+
+    /**
+     * 检查某用户在本轮是否已审核过某文件(按audit_start_date过滤)
+     */
+    int countByFileIdAndUserIdSinceTime(@Param("fileId") String fileId, @Param("auditUserId") String auditUserId, @Param("startTime") Date startTime);
+
+    /**
+     * 统计某文件的通过审核数
+     */
+    int countPassByFileId(String fileId);
+
+    /**
+     * 统计某文件本轮的通过审核数(按audit_start_date过滤)
+     */
+    int countPassByFileIdSinceTime(@Param("fileId") String fileId, @Param("startTime") Date startTime);
+
+    /**
+     * 统计某文件的驳回审核数
+     */
+    int countRejectByFileId(String fileId);
+
+    /**
+     * 统计某文件本轮的驳回审核数(按audit_start_date过滤)
+     */
+    int countRejectByFileIdSinceTime(@Param("fileId") String fileId, @Param("startTime") Date startTime);
+
+    /**
+     * 批量查询指定用户已审核过的文件ID列表(仅本轮审核:audit_time >= share.audit_start_date)
+     */
+    List<String> findAuditedFileIdsByUserId(String userId);
+
+    /**
+     * 根据文件ID逻辑删除所有审核记录(保留方法,如需作废可调用)
+     */
+    void logicDeleteByFileId(String fileId);
+}

+ 31 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBasePointDetailDao.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.UserPointDetail;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.UserPointSummary;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointDetail;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 知识库积分明细 DAO
+ * @author: 徐滕
+ * @version: 2026-05-19
+ */
+@MyBatisDao
+public interface WorkKnowledgeBasePointDetailDao extends CrudDao<WorkKnowledgeBasePointDetail> {
+
+    /** 用户积分汇总列表(经办人/部门/手机/总积分) */
+    List<UserPointSummary> findUserPointSummaryList(Map<String, Object> params);
+
+    /** 用户积分汇总总数 */
+    int findUserPointSummaryCount(Map<String, Object> params);
+
+    /** 某用户积分明细列表 */
+    List<UserPointDetail> findUserPointDetailList(Map<String, Object> params);
+
+    /** 某用户积分明细总数 */
+    int findUserPointDetailCount(Map<String, Object> params);
+}

+ 29 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBasePointRuleDao.java

@@ -0,0 +1,29 @@
+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.WorkKnowledgeBasePointRule;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 知识库积分规则 DAO
+ * @author: 徐滕
+ * @version: 2026-05-18
+ */
+@MyBatisDao
+public interface WorkKnowledgeBasePointRuleDao extends CrudDao<WorkKnowledgeBasePointRule> {
+
+    /**
+     * 根据规则类型查询启用的积分值
+     */
+    WorkKnowledgeBasePointRule findByRuleType(Integer ruleType);
+
+    /** 校验同 ruleType 是否已存在启用记录(排除自身 id) */
+    int countEnabledByRuleType(@Param("ruleType") Integer ruleType, @Param("excludeId") String excludeId);
+
+    /** 校验同名称是否已存在启用记录(排除自身 id) */
+    int countEnabledByPointName(@Param("pointName") String pointName, @Param("excludeId") String excludeId);
+
+    /** 切换状态 */
+    int updateStatus(@Param("id") String id, @Param("status") Integer status, @Param("updateBy") String updateBy);
+}

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

@@ -30,4 +30,9 @@ public interface WorkKnowledgeBaseShareInfoDao extends CrudDao<WorkKnowledgeBase
      * 根据节点id查询数据(用于删除校验等)
      */
     List<WorkKnowledgeBaseShareInfo> findByTreeNodeId(String treeNodeId);
+
+    /**
+     * 只更新审核状态及审核统计字段
+     */
+    int updateAuditStatus(WorkKnowledgeBaseShareInfo entity);
 }

+ 103 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/UserPointDetail.java

@@ -0,0 +1,103 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.util.Date;
+
+/**
+ * 用户积分明细实体类
+ * 用于展示某用户积分明细列表
+ * @author: 徐滕
+ * @version: 2026-05-19
+ */
+public class UserPointDetail extends DataEntity<UserPointDetail> {
+
+    /** ID */
+    private String id;
+
+    /** 用户ID */
+    private String userId;
+
+    /** 分享ID */
+    private String shareId;
+
+    /** 变动类型 1:创建加分 2:审核加分 */
+    private Integer changeType;
+
+    /** 积分值 */
+    private Integer point;
+
+    /** 分享名称 */
+    private String shareName;
+
+    /** 树节点ID */
+    private String treeNodeId;
+
+    /** 分享删除标志 */
+    private String shareDelFlag;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getShareId() {
+        return shareId;
+    }
+
+    public void setShareId(String shareId) {
+        this.shareId = shareId;
+    }
+
+    public Integer getChangeType() {
+        return changeType;
+    }
+
+    public void setChangeType(Integer changeType) {
+        this.changeType = changeType;
+    }
+
+    public Integer getPoint() {
+        return point;
+    }
+
+    public void setPoint(Integer point) {
+        this.point = point;
+    }
+
+    public String getShareName() {
+        return shareName;
+    }
+
+    public void setShareName(String shareName) {
+        this.shareName = shareName;
+    }
+
+    public String getTreeNodeId() {
+        return treeNodeId;
+    }
+
+    public void setTreeNodeId(String treeNodeId) {
+        this.treeNodeId = treeNodeId;
+    }
+
+    public String getShareDelFlag() {
+        return shareDelFlag;
+    }
+
+    public void setShareDelFlag(String shareDelFlag) {
+        this.shareDelFlag = shareDelFlag;
+    }
+}

+ 81 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/UserPointSummary.java

@@ -0,0 +1,81 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.util.Date;
+
+/**
+ * 用户积分汇总实体类
+ * 用于展示用户积分汇总列表(姓名/部门/手机/总积分)
+ * @author: 徐滕
+ * @version: 2026-05-19
+ */
+public class UserPointSummary extends DataEntity<UserPointSummary> {
+
+    /** 用户ID */
+    private String userId;
+
+    /** 用户姓名 */
+    private String userName;
+
+    /** 手机号 */
+    private String mobile;
+
+    /** 电话 */
+    private String phone;
+
+    /** 部门名称 */
+    private String officeName;
+
+    /** 总积分 */
+    private Integer totalPoint;
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getMobile() {
+        return mobile;
+    }
+
+    public void setMobile(String mobile) {
+        this.mobile = mobile;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    public String getOfficeName() {
+        return officeName;
+    }
+
+    public void setOfficeName(String officeName) {
+        this.officeName = officeName;
+    }
+
+    public Integer getTotalPoint() {
+        return totalPoint;
+    }
+
+    public void setTotalPoint(Integer totalPoint) {
+        this.totalPoint = totalPoint;
+    }
+}

+ 81 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseAuditRecord.java

@@ -0,0 +1,81 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.util.Date;
+
+/**
+ * 知识库审核记录表实体
+ * @author: 徐滕
+ * @version: 2026-05-18
+ */
+public class WorkKnowledgeBaseAuditRecord extends DataEntity<WorkKnowledgeBaseAuditRecord> {
+
+    /** 关联文件ID */
+    private String fileId;
+
+    /** 审核人ID(关联sys_user) */
+    private String auditUserId;
+
+    /** 审核结果 1:通过 2:驳回 */
+    private Integer auditResult;
+
+    /** 审核意见 */
+    private String auditOpinion;
+
+    /** 审核时间 */
+    private Date auditTime;
+
+    /** 审核人姓名(非数据库字段,通过audit_user_id关联sys_user查询) */
+    private String auditUserName;
+
+    public String getFileId() {
+        return fileId;
+    }
+
+    public void setFileId(String fileId) {
+        this.fileId = fileId;
+    }
+
+    public String getAuditUserId() {
+        return auditUserId;
+    }
+
+    public void setAuditUserId(String auditUserId) {
+        this.auditUserId = auditUserId;
+    }
+
+    public Integer getAuditResult() {
+        return auditResult;
+    }
+
+    public void setAuditResult(Integer auditResult) {
+        this.auditResult = auditResult;
+    }
+
+    public String getAuditOpinion() {
+        return auditOpinion;
+    }
+
+    public void setAuditOpinion(String auditOpinion) {
+        this.auditOpinion = auditOpinion;
+    }
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    public Date getAuditTime() {
+        return auditTime;
+    }
+
+    public void setAuditTime(Date auditTime) {
+        this.auditTime = auditTime;
+    }
+
+    public String getAuditUserName() {
+        return auditUserName;
+    }
+
+    public void setAuditUserName(String auditUserName) {
+        this.auditUserName = auditUserName;
+    }
+}

+ 56 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBasePointDetail.java

@@ -0,0 +1,56 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+
+/**
+ * 知识库积分明细表实体
+ * 对应表 work_knowledge_base_point_detail
+ * @author: 徐滕
+ * @version: 2026-05-19
+ */
+public class WorkKnowledgeBasePointDetail extends DataEntity<WorkKnowledgeBasePointDetail> {
+
+    /** 用户ID */
+    private String userId;
+
+    /** 知识库文件信息数据id(关联 work_knowledge_base_share_info.id) */
+    private String shareId;
+
+    /** 变动类型 1:创建加分 2:审核加分 */
+    private Integer changeType;
+
+    /** 积分值 */
+    private Integer point;
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getShareId() {
+        return shareId;
+    }
+
+    public void setShareId(String shareId) {
+        this.shareId = shareId;
+    }
+
+    public Integer getChangeType() {
+        return changeType;
+    }
+
+    public void setChangeType(Integer changeType) {
+        this.changeType = changeType;
+    }
+
+    public Integer getPoint() {
+        return point;
+    }
+
+    public void setPoint(Integer point) {
+        this.point = point;
+    }
+}

+ 77 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBasePointQuery.java

@@ -0,0 +1,77 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+import com.jeeplus.modules.sys.entity.Office;
+import com.jeeplus.modules.sys.entity.User;
+
+/**
+ * 知识库积分查询实体类
+ * 用于接收查询参数
+ * @author: 徐滕
+ * @version: 2026-05-19
+ */
+public class WorkKnowledgeBasePointQuery extends DataEntity<WorkKnowledgeBasePointQuery> {
+
+    /** 经办人姓名 */
+    private String userName;
+
+    /** 经办人部门ID */
+    private String officeId;
+
+    /** 经办人部门名称 */
+    private String officeName;
+    
+    /** 用于标识是否需要保存查询条件 */
+    private String toflag;
+    private User user;
+
+    private Office office;		// 所属部门
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getOfficeId() {
+        return officeId;
+    }
+
+    public void setOfficeId(String officeId) {
+        this.officeId = officeId;
+    }
+
+    public String getOfficeName() {
+        return officeName;
+    }
+
+    public void setOfficeName(String officeName) {
+        this.officeName = officeName;
+    }
+    
+    public String getToflag() {
+        return toflag;
+    }
+
+    public void setToflag(String toflag) {
+        this.toflag = toflag;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    public Office getOffice() {
+        return office;
+    }
+
+    public void setOffice(Office office) {
+        this.office = office;
+    }
+}

+ 55 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBasePointRule.java

@@ -0,0 +1,55 @@
+package com.jeeplus.modules.WorkKnowledgeBase.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+
+/**
+ * 知识库积分规则表实体
+ * @author: 徐滕
+ * @version: 2026-05-18
+ */
+public class WorkKnowledgeBasePointRule extends DataEntity<WorkKnowledgeBasePointRule> {
+
+    /** 规则类型 1:创建数据积分 2:审核通过积分 */
+    private Integer ruleType;
+
+    /** 积分值 */
+    private Integer pointValue;
+
+    /** 积分规则名称(手动填写,用于列表展示) */
+    private String pointName;
+
+    /** 状态 1启用 0禁用 */
+    private Integer status;
+
+    public Integer getRuleType() {
+        return ruleType;
+    }
+
+    public void setRuleType(Integer ruleType) {
+        this.ruleType = ruleType;
+    }
+
+    public Integer getPointValue() {
+        return pointValue;
+    }
+
+    public void setPointValue(Integer pointValue) {
+        this.pointValue = pointValue;
+    }
+
+    public String getPointName() {
+        return pointName;
+    }
+
+    public void setPointName(String pointName) {
+        this.pointName = pointName;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+}

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

@@ -20,6 +20,21 @@ public class WorkKnowledgeBaseShareInfo extends DataEntity<WorkKnowledgeBaseShar
     private String name;       // 上传文件名称
     private Date createTime;      // 创建时间
 
+    /** 审核状态 0:草稿 1:未审核 2:审核中 4:审核未通过 5:审核通过 */
+    private String auditStatus;
+
+    /** 已通过审核人数 */
+    private Integer auditPassCount;
+
+    /** 已驳回审核人数 */
+    private Integer auditRejectCount;
+
+    /** 提交审核人ID(谁上传并提交,审核积分归属此人) */
+    private String submitAuditUserId;
+
+    /** 本轮审核起始时间(每次提交审核时刷新;用于过滤本轮审核记录、隔离历史驳回数据) */
+    private Date auditStartDate;
+
     /** 所属根节点id(用于查询动态字段,非数据库字段) */
     private String rootId;
 
@@ -147,4 +162,44 @@ public class WorkKnowledgeBaseShareInfo extends DataEntity<WorkKnowledgeBaseShar
     public void setWorkAttachments(List<Workattachment> workAttachments) {
         this.workAttachments = workAttachments;
     }
+
+    public String getAuditStatus() {
+        return auditStatus;
+    }
+
+    public void setAuditStatus(String auditStatus) {
+        this.auditStatus = auditStatus;
+    }
+
+    public Integer getAuditPassCount() {
+        return auditPassCount;
+    }
+
+    public void setAuditPassCount(Integer auditPassCount) {
+        this.auditPassCount = auditPassCount;
+    }
+
+    public Integer getAuditRejectCount() {
+        return auditRejectCount;
+    }
+
+    public void setAuditRejectCount(Integer auditRejectCount) {
+        this.auditRejectCount = auditRejectCount;
+    }
+
+    public String getSubmitAuditUserId() {
+        return submitAuditUserId;
+    }
+
+    public void setSubmitAuditUserId(String submitAuditUserId) {
+        this.submitAuditUserId = submitAuditUserId;
+    }
+
+    public Date getAuditStartDate() {
+        return auditStartDate;
+    }
+
+    public void setAuditStartDate(Date auditStartDate) {
+        this.auditStartDate = auditStartDate;
+    }
 }

+ 64 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseAuditRecordService.java

@@ -0,0 +1,64 @@
+package com.jeeplus.modules.WorkKnowledgeBase.service;
+
+import com.jeeplus.common.service.CrudService;
+import com.jeeplus.common.utils.IdGen;
+import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseAuditRecordDao;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseAuditRecord;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 知识库审核记录 Service
+ * @author: 徐滕
+ * @version: 2026-05-18
+ */
+@Service
+@Transactional(readOnly = true)
+public class WorkKnowledgeBaseAuditRecordService extends CrudService<WorkKnowledgeBaseAuditRecordDao, WorkKnowledgeBaseAuditRecord> {
+
+    @Autowired
+    private WorkKnowledgeBaseAuditRecordDao auditRecordDao;
+
+    /**
+     * 根据文件ID查询审核记录列表(按审核时间倒序)
+     */
+    public List<WorkKnowledgeBaseAuditRecord> findByFileId(String fileId) {
+        return auditRecordDao.findByFileId(fileId);
+    }
+
+    /**
+     * 检查某用户是否已审核过某文件
+     */
+    public boolean hasAudited(String fileId, String auditUserId) {
+        return auditRecordDao.countByFileIdAndUserId(fileId, auditUserId) > 0;
+    }
+
+    /**
+     * 统计某文件的通过审核数
+     */
+    public int countPassByFileId(String fileId) {
+        return auditRecordDao.countPassByFileId(fileId);
+    }
+
+    /**
+     * 统计某文件的驳回审核数
+     */
+    public int countRejectByFileId(String fileId) {
+        return auditRecordDao.countRejectByFileId(fileId);
+    }
+
+    /**
+     * 保存审核记录
+     */
+    @Transactional(readOnly = false)
+    public void saveAuditRecord(WorkKnowledgeBaseAuditRecord record) {
+        record.setId(IdGen.uuid());
+        record.setAuditTime(new Date());
+        record.preInsert();
+        auditRecordDao.insert(record);
+    }
+}

+ 108 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBasePointDetailService.java

@@ -0,0 +1,108 @@
+package com.jeeplus.modules.WorkKnowledgeBase.service;
+
+import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.service.CrudService;
+import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBasePointDetailDao;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.UserPointDetail;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.UserPointSummary;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointDetail;
+import com.jeeplus.modules.sys.service.OfficeService;
+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: 徐滕
+ * @version: 2026-05-19
+ */
+@Service
+@Transactional(readOnly = true)
+public class WorkKnowledgeBasePointDetailService extends CrudService<WorkKnowledgeBasePointDetailDao, WorkKnowledgeBasePointDetail> {
+
+    @Autowired
+    private WorkKnowledgeBasePointDetailDao pointDetailDao;
+
+    @Autowired
+    private OfficeService officeService;
+
+    /**
+     * 用户积分汇总分页查询
+     * @param page          分页对象
+     * @param userName      姓名模糊
+     * @param officeId      部门ID
+     */
+    public Page<UserPointSummary> findUserPointSummaryPage(Page<UserPointSummary> page,
+                                                              String userName, String officeId) {
+        Map<String, Object> params = new HashMap<>();
+        if (StringUtils.isNotBlank(userName)) params.put("userName", userName.trim());
+
+        // 处理部门ID查询逻辑
+        if (StringUtils.isNotBlank(officeId)) {
+            // 查询该选择节点下所有的部门Id
+            List<String> officeIdList = officeService.getChildrenOffice(officeId);
+            officeIdList.add(officeId);
+            params.put("officeIdList", officeIdList);
+        }
+
+        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 = pointDetailDao.findUserPointSummaryCount(params);
+        page.setCount(count);
+        page.setCountFlag(false);
+        if (count > 0) {
+            page.setList(pointDetailDao.findUserPointSummaryList(params));
+        } else {
+            page.setList(new ArrayList<>());
+        }
+        return page;
+    }
+
+    /**
+     * 用户积分明细分页查询
+     * @param page          分页对象
+     * @param userId        必传
+     * @param shareName     文档名模糊
+     * @param changeType    1=创建 2=审核
+     * @param beginDate     起
+     * @param endDate       止
+     */
+    public Page<UserPointDetail> findUserPointDetailPage(Page<UserPointDetail> page,
+                                                             String userId,
+                                                             String shareName,
+                                                             Integer changeType,
+                                                             String beginDate,
+                                                             String endDate) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("userId", userId);
+        if (StringUtils.isNotBlank(shareName)) params.put("shareName", shareName.trim());
+        if (changeType != null) params.put("changeType", changeType);
+        if (StringUtils.isNotBlank(beginDate)) params.put("beginDate", beginDate.trim());
+        if (StringUtils.isNotBlank(endDate)) params.put("endDate", endDate.trim());
+
+        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 = pointDetailDao.findUserPointDetailCount(params);
+        page.setCount(count);
+        page.setCountFlag(false);
+        if (count > 0) {
+            page.setList(pointDetailDao.findUserPointDetailList(params));
+        } else {
+            page.setList(new ArrayList<>());
+        }
+        return page;
+    }
+}

+ 104 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBasePointRuleService.java

@@ -0,0 +1,104 @@
+package com.jeeplus.modules.WorkKnowledgeBase.service;
+
+import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.service.CrudService;
+import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBasePointRuleDao;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointRule;
+import com.jeeplus.modules.sys.entity.User;
+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;
+
+/**
+ * 知识库积分规则配置 Service
+ * 提供:分页查询、保存、删除、状态切换
+ * @author: 徐滕
+ * @version: 2026-05-19
+ */
+@Service
+@Transactional(readOnly = true)
+public class WorkKnowledgeBasePointRuleService extends CrudService<WorkKnowledgeBasePointRuleDao, WorkKnowledgeBasePointRule> {
+
+    @Autowired
+    private WorkKnowledgeBasePointRuleDao pointRuleDao;
+
+    /** 分页查询(标准框架模式) */
+    public Page<WorkKnowledgeBasePointRule> findPage(Page<WorkKnowledgeBasePointRule> page, WorkKnowledgeBasePointRule entity) {
+        return super.findPage(page, entity);
+    }
+
+    /** 查询单条(编辑回显) */
+    public WorkKnowledgeBasePointRule getById(String id) {
+        if (StringUtils.isBlank(id)) return new WorkKnowledgeBasePointRule();
+        WorkKnowledgeBasePointRule rule = pointRuleDao.get(id);
+        return rule != null ? rule : new WorkKnowledgeBasePointRule();
+    }
+
+    /**
+     * 保存(新增/更新)
+     * 校验:
+     *  - pointName / pointValue 必填
+     *  - 启用状态下同名称只能存在一条
+     * @return 错误信息,null 表示成功
+     */
+    @Transactional(readOnly = false)
+    public String saveRule(WorkKnowledgeBasePointRule entity) {
+        if (entity == null) {
+            return "参数异常";
+        }
+        if (StringUtils.isBlank(entity.getPointName())) {
+            return "规则名称不能为空";
+        }
+        if (entity.getPointValue() == null || entity.getPointValue() < 0) {
+            return "积分值必须为非负整数";
+        }
+        if (entity.getStatus() == null) {
+            entity.setStatus(1);
+        }
+        // 唯一性校验:启用态同名称唯一
+        if (entity.getStatus() != null && entity.getStatus() == 1) {
+            int dup = pointRuleDao.countEnabledByPointName(entity.getPointName().trim(), entity.getId());
+            if (dup > 0) {
+                return "该规则名称已存在启用记录,请先禁用原有记录或直接编辑";
+            }
+        }
+        if (StringUtils.isBlank(entity.getId())) {
+            entity.preInsert();
+            pointRuleDao.insert(entity);
+        } else {
+            entity.preUpdate();
+            pointRuleDao.update(entity);
+        }
+        return null;
+    }
+
+    /** 逻辑删除 */
+    @Transactional(readOnly = false)
+    public void deleteRule(String id) {
+        if (StringUtils.isBlank(id)) return;
+        WorkKnowledgeBasePointRule entity = new WorkKnowledgeBasePointRule();
+        entity.setId(id);
+        pointRuleDao.deleteByLogic(entity);
+    }
+
+    /** 切换状态 */
+    @Transactional(readOnly = false)
+    public String toggleStatus(String id, Integer status) {
+        if (StringUtils.isBlank(id) || status == null) return "参数缺失";
+        // 启用前唯一性校验(同名称启用态唯一)
+        if (status == 1) {
+            WorkKnowledgeBasePointRule current = pointRuleDao.get(id);
+            if (current == null) return "记录不存在";
+            int dup = pointRuleDao.countEnabledByPointName(current.getPointName(), id);
+            if (dup > 0) {
+                return "该规则名称已存在启用记录,请先禁用其它记录";
+            }
+        }
+        User user = UserUtils.getUser();
+        String updateBy = user != null ? user.getId() : "";
+        pointRuleDao.updateStatus(id, status, updateBy);
+        return null;
+    }
+}

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

@@ -4,11 +4,15 @@ 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.WorkKnowledgeBaseAuditRecordDao;
 import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseDynamicInfoDao;
 import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseDynamicValueInfoDao;
+import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBasePointDetailDao;
+import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBasePointRuleDao;
 import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseShareInfoDao;
 import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBaseTreeInfoDao;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.*;
+import com.jeeplus.modules.sys.entity.User;
 import com.jeeplus.modules.sys.entity.Workattachment;
 import com.jeeplus.modules.sys.service.WorkattachmentService;
 import com.jeeplus.modules.sys.utils.UserUtils;
@@ -17,9 +21,12 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * 知识库-文件信息 Service
@@ -33,6 +40,29 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
     /** 附件标识(attachmentFlag),进行隔离不同业务的附件 */
     private static final String ATTACHMENT_FLAG = "199";
 
+    /** 审核状态常量:草稿 */
+    public static final String AUDIT_STATUS_DRAFT = "0";
+    /** 审核状态常量:未审核 */
+    public static final String AUDIT_STATUS_PENDING = "1";
+    /** 审核状态常量:审核中 */
+    public static final String AUDIT_STATUS_AUDITING = "2";
+    /** 审核状态常量:审核未通过 */
+    public static final String AUDIT_STATUS_REJECTED = "4";
+    /** 审核状态常量:审核通过 */
+    public static final String AUDIT_STATUS_PASSED = "5";
+
+    /** 审核通过所需人数 */
+    public static final int AUDIT_PASS_REQUIRED = 3;
+
+    /** 积分规则类型:创建数据积分 */
+    private static final Integer POINT_RULE_CREATE = 1;
+    /** 积分规则类型:审核通过积分 */
+    private static final Integer POINT_RULE_AUDIT = 2;
+    /** 积分明细变动类型:创建加分 */
+    private static final Integer POINT_CHANGE_CREATE = 1;
+    /** 积分明细变动类型:审核加分 */
+    private static final Integer POINT_CHANGE_AUDIT = 2;
+
     @Autowired
     private WorkKnowledgeBaseDynamicInfoDao dynamicInfoDao;
 
@@ -43,8 +73,17 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
     private WorkKnowledgeBaseTreeInfoDao treeInfoDao;
 
     @Autowired
+    private WorkKnowledgeBaseAuditRecordDao auditRecordDao;
+
+    @Autowired
     private WorkattachmentService workattachmentService;
 
+    @Autowired
+    private WorkKnowledgeBasePointDetailDao pointDetailDao;
+
+    @Autowired
+    private WorkKnowledgeBasePointRuleDao pointRuleDao;
+
     /**
      * 根据文件id加载附件列表(编辑表单回显用)
      */
@@ -108,6 +147,16 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
             }
             // 处理附件url
             workattachmentService.attachmentManageByUrlOnWorkKnowledgeBaseShare(list);
+
+            // 标记当前登录用户是否已对列表中的文件审核过
+            String currentUserId = UserUtils.getUser().getId();
+            List<String> auditedIds = auditRecordDao.findAuditedFileIdsByUserId(currentUserId);
+            Set<String> auditedIdSet = new HashSet<>(auditedIds);
+            for (Map<String, Object> map : list) {
+                Object fileId = map.get("id");
+                map.put("currentUserAudited", fileId != null && auditedIdSet.contains(fileId.toString()));
+            }
+
             page.setList(list);
         } else {
             page.setList(new ArrayList<>());
@@ -147,6 +196,41 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
             }
         }
 
+        // ========== 审核状态自动判定逻辑 ==========
+        // 根据附件有无自动赋值 audit_status:无文件->草稿0,有文件->未审核 1
+        // 审核未通过重新编辑保存时也按此规则处理
+        boolean hasValidAttachment = hasValidAttachment(attachments);
+        // 编辑时,若前端未提交附件列表(用户未更换文件),回查DB已有附件进行判定
+        if (!isNew && (attachments == null || attachments.isEmpty()) && StringUtils.isNotBlank(shareInfo.getId())) {
+            List<Workattachment> existingAttachments = findAttachmentsByFileId(shareInfo.getId());
+            hasValidAttachment = hasValidAttachment(existingAttachments);
+        }
+        if (isNew) {
+            // 新增:无文件草稿0,有文件未审核 1
+            shareInfo.setAuditStatus(hasValidAttachment ? AUDIT_STATUS_PENDING : AUDIT_STATUS_DRAFT);
+            shareInfo.setAuditPassCount(0);
+            shareInfo.setAuditRejectCount(0);
+            // 有附件时记录提交审核人为当前登录人,同时初始化本轮审核起始时间
+            if (hasValidAttachment) {
+                shareInfo.setSubmitAuditUserId(UserUtils.getUser().getId());
+                shareInfo.setAuditStartDate(new Date());
+            }
+        } else {
+            // 编辑:仅当状态为草稿(0)或审核未通过(4)时允许重新判定
+            String currentStatus = shareInfo.getAuditStatus();
+            if (currentStatus != null && (currentStatus.equals(AUDIT_STATUS_DRAFT) || currentStatus.equals(AUDIT_STATUS_REJECTED))) {
+                shareInfo.setAuditStatus(hasValidAttachment ? AUDIT_STATUS_PENDING : AUDIT_STATUS_DRAFT);
+                shareInfo.setAuditPassCount(0);
+                shareInfo.setAuditRejectCount(0);
+                // 重新提交时更新提交审核人为当前登录人,并刷新本轮审核起始时间(历史审核记录依靠该时间隔离)
+                if (hasValidAttachment) {
+                    shareInfo.setSubmitAuditUserId(UserUtils.getUser().getId());
+                    shareInfo.setAuditStartDate(new Date());
+                }
+            }
+            // 审核中(2)和审核通过(5)不允许编辑,由Controller层校验
+        }
+
         if (isNew) {
             shareInfo.setId(IdGen.uuid());
             shareInfo.preInsert();
@@ -199,6 +283,288 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
     }
 
     /**
+     * 判断附件列表中是否存在有效(未删除的)附件
+     */
+    private boolean hasValidAttachment(List<Workattachment> attachments) {
+        if (attachments == null || attachments.isEmpty()) {
+            return false;
+        }
+        for (Workattachment attachment : attachments) {
+            if (attachment.getId() != null
+                    && Workattachment.DEL_FLAG_NORMAL.equals(attachment.getDelFlag())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 发起审核:未审核(1) -> 审核中(2),清空通过/驳回统计
+     */
+    @Transactional(readOnly = false)
+    public void submitAudit(String fileId) {
+        WorkKnowledgeBaseShareInfo entity = dao.get(fileId);
+        if (entity == null) {
+            throw new RuntimeException("文件记录不存在");
+        }
+        if (entity.getAuditStatus() == null || entity.getAuditStatus() != AUDIT_STATUS_PENDING) {
+            throw new RuntimeException("当前状态不允许发起审核");
+        }
+        entity.setAuditStatus(AUDIT_STATUS_AUDITING);
+        entity.setAuditPassCount(0);
+        entity.setAuditRejectCount(0);
+        // 刷新本轮审核起始时间
+        entity.setAuditStartDate(new Date());
+        entity.preUpdate();
+        dao.updateAuditStatus(entity);
+    }
+
+    /**
+     * 审核通过操作
+     * 规则:本轮三人通过即成功(仅统计 audit_start_date 之后的记录,隔离历史数据)
+     */
+    @Transactional(readOnly = false)
+    public void auditPass(String fileId, String auditUserId, String auditOpinion) {
+        WorkKnowledgeBaseShareInfo entity = dao.get(fileId);
+        if (entity == null) {
+            throw new RuntimeException("文件记录不存在");
+        }
+        if (entity.getAuditStatus() == null || entity.getAuditStatus() == AUDIT_STATUS_REJECTED || entity.getAuditStatus() == AUDIT_STATUS_PASSED) {
+            throw new RuntimeException("当前状态不允许审核");
+        }
+        // 禁止审核自己提交的文件
+        if (auditUserId.equals(entity.getSubmitAuditUserId())) {
+            throw new RuntimeException("不允许审核自己提交的文件");
+        }
+        // 检查本轮是否已审核过(按 audit_start_date 过滤,避免历史记录干扰)
+        Date startTime = entity.getAuditStartDate();
+        if (auditRecordDao.countByFileIdAndUserIdSinceTime(fileId, auditUserId, startTime) > 0) {
+            throw new RuntimeException("您已审核过该文件,不可重复审核");
+        }
+        // 保存审核记录
+        WorkKnowledgeBaseAuditRecord record = new WorkKnowledgeBaseAuditRecord();
+        record.setFileId(fileId);
+        record.setAuditUserId(auditUserId);
+        record.setAuditResult(1); // 1:通过
+        record.setAuditOpinion(auditOpinion);
+        record.setId(IdGen.uuid());
+        record.setAuditTime(new java.util.Date());
+        record.preInsert();
+        auditRecordDao.insert(record);
+
+        // 更新通过计数(仅统计本轮)
+        int passCount = auditRecordDao.countPassByFileIdSinceTime(fileId, startTime);
+        entity.setAuditPassCount(passCount);
+        entity.setAuditRejectCount(auditRecordDao.countRejectByFileIdSinceTime(fileId, startTime));
+
+        // 判定:本轮累计3人通过则审核通过;否则进入审核中状态(一旦有人开始审核,状态即变为2)
+        if (passCount >= AUDIT_PASS_REQUIRED) {
+            entity.setAuditStatus(AUDIT_STATUS_PASSED);
+            entity.preUpdate();
+            dao.updateAuditStatus(entity);
+            // 本轮审核通过:为提交审核人及本轮三位审核人写入积分明细
+            grantPointsOnAuditPassed(entity, startTime);
+        } else {
+            entity.setAuditStatus(AUDIT_STATUS_AUDITING);
+            entity.preUpdate();
+            dao.updateAuditStatus(entity);
+        }
+    }
+
+    /**
+     * 审核驳回操作
+     * 规则:一票驳回直接审核失败;历史记录依靠 audit_start_date 隔离,无需逻辑删除
+     */
+    @Transactional(readOnly = false)
+    public void auditReject(String fileId, String auditUserId, String auditOpinion) {
+        WorkKnowledgeBaseShareInfo entity = dao.get(fileId);
+        if (entity == null) {
+            throw new RuntimeException("文件记录不存在");
+        }
+        if (entity.getAuditStatus() == null || entity.getAuditStatus() == AUDIT_STATUS_REJECTED || entity.getAuditStatus() == AUDIT_STATUS_PASSED) {
+            throw new RuntimeException("当前状态不允许审核");
+        }
+        // 禁止审核自己提交的文件
+        if (auditUserId.equals(entity.getSubmitAuditUserId())) {
+            throw new RuntimeException("不允许审核自己提交的文件");
+        }
+        // 检查本轮是否已审核过
+        Date startTime = entity.getAuditStartDate();
+        if (auditRecordDao.countByFileIdAndUserIdSinceTime(fileId, auditUserId, startTime) > 0) {
+            throw new RuntimeException("您已审核过该文件,不可重复审核");
+        }
+        // 保存审核记录
+        WorkKnowledgeBaseAuditRecord record = new WorkKnowledgeBaseAuditRecord();
+        record.setFileId(fileId);
+        record.setAuditUserId(auditUserId);
+        record.setAuditResult(2); // 2:驳回
+        record.setAuditOpinion(auditOpinion);
+        record.setId(IdGen.uuid());
+        record.setAuditTime(new java.util.Date());
+        record.preInsert();
+        auditRecordDao.insert(record);
+
+        // 一票驳回直接变为审核未通过(历史记录保留,重新提交后 audit_start_date 刷新自动隔离)
+        entity.setAuditStatus(AUDIT_STATUS_REJECTED);
+        entity.setAuditPassCount(auditRecordDao.countPassByFileIdSinceTime(fileId, startTime));
+        entity.setAuditRejectCount(auditRecordDao.countRejectByFileIdSinceTime(fileId, startTime));
+        entity.preUpdate();
+        dao.updateAuditStatus(entity);
+    }
+
+    /**
+     * 撤回审核:审核中(1/2) -> 草稿(0)
+     * 仅提交审核人或管理员可撤回。历史记录依靠 audit_start_date 隔离,无需逻辑删除
+     */
+    @Transactional(readOnly = false)
+    public void withdrawAudit(String fileId) {
+        WorkKnowledgeBaseShareInfo entity = dao.get(fileId);
+        if (entity == null) {
+            throw new RuntimeException("文件记录不存在");
+        }
+        if (entity.getAuditStatus() == null || entity.getAuditStatus() == AUDIT_STATUS_REJECTED || entity.getAuditStatus() == AUDIT_STATUS_PASSED) {
+            throw new RuntimeException("当前状态不允许撤回");
+        }
+        // 校验权限:仅提交审核人或管理员可撤回
+        User currentUser = UserUtils.getUser();
+        if (!currentUser.isAdmin() && !UserUtils.isManager()
+                && !currentUser.getId().equals(entity.getSubmitAuditUserId())) {
+            throw new RuntimeException("您没有权限撤回该审核");
+        }
+        entity.setAuditStatus(AUDIT_STATUS_DRAFT);
+        entity.setAuditPassCount(0);
+        entity.setAuditRejectCount(0);
+        entity.preUpdate();
+        dao.updateAuditStatus(entity);
+    }
+
+    /**
+     * 判断当前用户是否可以编辑指定文件
+     */
+    public boolean canEdit(WorkKnowledgeBaseShareInfo entity) {
+        if (entity == null || entity.getAuditStatus() == null) return true;
+        String status = entity.getAuditStatus();
+        User currentUser = UserUtils.getUser();
+        boolean isAdmin = currentUser.isAdmin() || UserUtils.isManager();
+
+        switch (status) {
+            case "0": // 草稿:所有用户可修改
+            case "1": // 未审核:所有用户可修改
+            case "4": // 审核未通过:所有用户可修改
+                return true;
+            case "2": // 审核中:全员禁止修改
+                return false;
+            case "5": // 审核通过:仅管理员可修改
+                return isAdmin;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * 判断当前用户是否可以删除指定文件
+     */
+    public boolean canDelete(WorkKnowledgeBaseShareInfo entity) {
+        // 删除权限与编辑权限逻辑一致
+        return canEdit(entity);
+    }
+
+    /**
+     * 判断当前用户是否可以撤回审核
+     */
+    public boolean canWithdraw(WorkKnowledgeBaseShareInfo entity) {
+        if (entity == null || entity.getAuditStatus() == null) return false;
+        if (entity.getAuditStatus() != AUDIT_STATUS_PENDING && entity.getAuditStatus() != AUDIT_STATUS_AUDITING) return false;
+        User currentUser = UserUtils.getUser();
+        return currentUser.isAdmin() || UserUtils.isManager()
+                || currentUser.getId().equals(entity.getSubmitAuditUserId());
+    }
+
+    /**
+     * 判断当前用户是否可以审核(通过/驳回)该文件
+     */
+    public boolean canAudit(WorkKnowledgeBaseShareInfo entity) {
+        if (entity == null || entity.getAuditStatus() == null) return false;
+        if (entity.getAuditStatus() != AUDIT_STATUS_PENDING && entity.getAuditStatus() != AUDIT_STATUS_AUDITING) return false;
+        String currentUserId = UserUtils.getUser().getId();
+        // 提交审核人不可审核自己的文件
+        if (currentUserId.equals(entity.getSubmitAuditUserId())) return false;
+        // 本轮未审核过的用户可审核(按 audit_start_date 隔离历史记录)
+        return auditRecordDao.countByFileIdAndUserIdSinceTime(entity.getId(), currentUserId, entity.getAuditStartDate()) == 0;
+    }
+
+    /**
+     * 判断当前用户是否可以发起审核
+     */
+    public boolean canSubmitAudit(WorkKnowledgeBaseShareInfo entity) {
+        if (entity == null || entity.getAuditStatus() == null) return false;
+        return entity.getAuditStatus() == AUDIT_STATUS_PENDING
+                || entity.getAuditStatus() == AUDIT_STATUS_REJECTED;
+    }
+
+    /**
+     * 根据文件id查询本轮审核记录列表(详情页仅展示 audit_start_date 之后的记录,驳回后历史记录不可见)
+     */
+    public List<WorkKnowledgeBaseAuditRecord> findAuditRecordsByFileId(String fileId) {
+        WorkKnowledgeBaseShareInfo entity = dao.get(fileId);
+        Date startTime = entity != null ? entity.getAuditStartDate() : null;
+        return auditRecordDao.findByFileIdSinceTime(fileId, startTime);
+    }
+
+    /**
+     * 本轮审核通过后发放积分:
+     * 1、为提交审核人(submit_audit_user_id)发放创建积分(change_type=1)
+     * 2、为本轮三位审核人(audit_time >= audit_start_date 且 audit_result=1)各发放审核积分(change_type=2)
+     * 积分值读取 work_knowledge_base_point_rule 中对应 status=1 的启用规则
+     */
+    private void grantPointsOnAuditPassed(WorkKnowledgeBaseShareInfo entity, Date startTime) {
+        if (entity == null) {
+            return;
+        }
+        String shareId = entity.getId();
+        // 1、提交审核人获得创建积分
+        String submitUserId = entity.getSubmitAuditUserId();
+        if (StringUtils.isNotBlank(submitUserId)) {
+            WorkKnowledgeBasePointRule createRule = pointRuleDao.findByRuleType(POINT_RULE_CREATE);
+            if (createRule != null && createRule.getPointValue() != null && createRule.getPointValue() > 0) {
+                insertPointDetail(submitUserId, shareId, POINT_CHANGE_CREATE, createRule.getPointValue());
+            }
+        }
+        // 2、本轮三位审核人各获得审核积分(仅统计 audit_result=1 且 audit_time >= startTime)
+        WorkKnowledgeBasePointRule auditRule = pointRuleDao.findByRuleType(POINT_RULE_AUDIT);
+        if (auditRule == null || auditRule.getPointValue() == null || auditRule.getPointValue() <= 0) {
+            return;
+        }
+        List<WorkKnowledgeBaseAuditRecord> records = auditRecordDao.findByFileIdSinceTime(shareId, startTime);
+        if (records == null || records.isEmpty()) {
+            return;
+        }
+        Set<String> grantedUserIds = new HashSet<>();
+        for (WorkKnowledgeBaseAuditRecord record : records) {
+            // 只给本轮审核通过的人加分,同一人只加一次
+            if (record.getAuditResult() != null && record.getAuditResult() == 1
+                    && StringUtils.isNotBlank(record.getAuditUserId())
+                    && grantedUserIds.add(record.getAuditUserId())) {
+                insertPointDetail(record.getAuditUserId(), shareId, POINT_CHANGE_AUDIT, auditRule.getPointValue());
+            }
+        }
+    }
+
+    /**
+     * 插入一条积分明细记录
+     */
+    private void insertPointDetail(String userId, String shareId, Integer changeType, Integer point) {
+        WorkKnowledgeBasePointDetail detail = new WorkKnowledgeBasePointDetail();
+        detail.setId(IdGen.uuid());
+        detail.setUserId(userId);
+        detail.setShareId(shareId);
+        detail.setChangeType(changeType);
+        detail.setPoint(point);
+        detail.preInsert();
+        pointDetailDao.insert(detail);
+    }
+
+    /**
      * 逻辑删除文件(含动态字段值)
      */
     @Transactional(readOnly = false)

+ 117 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBasePointController.java

@@ -0,0 +1,117 @@
+package com.jeeplus.modules.WorkKnowledgeBase.web;
+
+import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.common.web.BaseController;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.UserPointSummary;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.UserPointDetail;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointQuery;
+import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBasePointDetailService;
+import com.jeeplus.modules.sys.entity.Office;
+import com.jeeplus.modules.sys.service.OfficeService;
+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.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 知识库积分管理 Controller
+ * 主列表:人员积分汇总;子页:用户积分明细
+ * @author: 徐滕
+ * @version: 2026-05-19
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/workKnowledgeBase/point")
+public class WorkKnowledgeBasePointController extends BaseController {
+
+    @Autowired
+    private WorkKnowledgeBasePointDetailService pointService;
+
+    @Autowired
+    private OfficeService officeService;
+
+    @ModelAttribute
+    public WorkKnowledgeBasePointQuery get(@RequestParam(required = false) String id) {
+        WorkKnowledgeBasePointQuery entity = null;
+        if (StringUtils.isNotBlank(id)){
+            //entity = (WorkKnowledgeBasePointQuery) pointService.get(id);
+        }
+        if (entity == null){
+            entity = new WorkKnowledgeBasePointQuery();
+        }
+        return entity;
+    }
+
+    /**
+     * 人员积分汇总列表
+     * 参数:userName(经办人模糊)、officeId(经办人部门ID)
+     */
+    @RequiresPermissions("workKnowledgeBase:point:list")
+    @RequestMapping(value = {"userList", ""})
+    public String userList(WorkKnowledgeBasePointQuery workKnowledgeBasePointQuery, HttpServletRequest request, HttpServletResponse response, Model model) {
+        //进行查询之后进行任何操作,返回还是查询之后的数据页面
+        if (StringUtils.isNotBlank(workKnowledgeBasePointQuery.getToflag())){
+            if (workKnowledgeBasePointQuery.getToflag().equals("1")){
+                request.getSession().removeAttribute("searchPoint");
+                WorkKnowledgeBasePointQuery searchPoint = workKnowledgeBasePointQuery;
+                request.getSession().setAttribute("searchPoint", searchPoint);
+            }
+        }else{
+            if (request.getSession().getAttribute("searchPoint")!=null){
+                workKnowledgeBasePointQuery = (WorkKnowledgeBasePointQuery) request.getSession().getAttribute("searchPoint");
+            }
+        }
+        //判断经办人是否为空,为空则赋值为null 防止查找为空的数据
+        if(StringUtils.isBlank(workKnowledgeBasePointQuery.getUserName())){
+            workKnowledgeBasePointQuery.setUserName(null);
+        }
+        Page<UserPointSummary> page = pointService.findUserPointSummaryPage(
+                new Page<>(request, response), workKnowledgeBasePointQuery.getUserName(), workKnowledgeBasePointQuery.getOfficeId());
+        model.addAttribute("page", page);
+        model.addAttribute("workKnowledgeBasePointQuery", workKnowledgeBasePointQuery);
+        // 获取部门名称用于显示
+        String officeName = null;
+        if (StringUtils.isNotBlank(workKnowledgeBasePointQuery.getOfficeId())) {
+            Office office = officeService.get(workKnowledgeBasePointQuery.getOfficeId());
+            if (office != null) {
+                officeName = office.getName();
+            }
+        }
+        model.addAttribute("officeName", officeName);
+        return "modules/WorkKnowledgeBase/workKnowledgeBasePointUserList";
+    }
+
+    /**
+     * 某用户积分明细列表(子页)
+     * 参数:userId(必传)、shareName(文档名模糊)、changeType(1创建/2审核)、beginDate、endDate
+     */
+    @RequiresPermissions("workKnowledgeBase:point:list")
+    @RequestMapping(value = "userDetail")
+    public String userDetail(@RequestParam("userId") String userId,
+                             @RequestParam(required = false) String userName,
+                             @RequestParam(required = false) String shareName,
+                             @RequestParam(required = false) Integer changeType,
+                             @RequestParam(required = false) String beginDate,
+                             @RequestParam(required = false) String endDate,
+                             HttpServletRequest request, HttpServletResponse response, Model model) {
+        if (StringUtils.isBlank(userId)) {
+            model.addAttribute("message", "用户ID不能为空");
+        }
+        Page<UserPointDetail> page = pointService.findUserPointDetailPage(
+                new Page<>(request, response), userId, shareName, changeType, beginDate, endDate);
+        model.addAttribute("page", page);
+        model.addAttribute("userId", userId);
+        model.addAttribute("userName", userName);
+        model.addAttribute("shareName", shareName);
+        model.addAttribute("changeType", changeType);
+        model.addAttribute("beginDate", beginDate);
+        model.addAttribute("endDate", endDate);
+        return "modules/WorkKnowledgeBase/workKnowledgeBasePointUserDetail";
+    }
+}

+ 112 - 0
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBasePointRuleController.java

@@ -0,0 +1,112 @@
+package com.jeeplus.modules.WorkKnowledgeBase.web;
+
+import com.jeeplus.common.config.Global;
+import com.jeeplus.common.json.AjaxJson;
+import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.common.web.BaseController;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointRule;
+import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBasePointRuleService;
+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.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 知识库积分规则配置 Controller
+ * 提供:列表、表单、保存、删除、状态切换
+ * @author: 徐滕
+ * @version: 2026-05-19
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/workKnowledgeBase/pointRule")
+public class WorkKnowledgeBasePointRuleController extends BaseController {
+
+    @Autowired
+    private WorkKnowledgeBasePointRuleService pointRuleService;
+
+    @ModelAttribute
+    public WorkKnowledgeBasePointRule get(@RequestParam(required = false) String id) {
+        if (StringUtils.isNotBlank(id)) {
+            return pointRuleService.getById(id);
+        }
+        return new WorkKnowledgeBasePointRule();
+    }
+
+    /** 列表页 */
+    @RequiresPermissions("workKnowledgeBase:pointRule:list")
+    @RequestMapping(value = {"list", ""})
+    public String list(WorkKnowledgeBasePointRule workKnowledgeBasePointRule, HttpServletRequest request, HttpServletResponse response, Model model) {
+        Page<WorkKnowledgeBasePointRule> page = pointRuleService.findPage(new Page<WorkKnowledgeBasePointRule>(request, response), workKnowledgeBasePointRule);
+        System.out.println("[DEBUG] 积分规则列表 - 总记录数: " + page.getCount());
+        System.out.println("[DEBUG] 积分规则列表 - 当前页数据量: " + (page.getList() != null ? page.getList().size() : 0));
+        if (page.getList() != null && !page.getList().isEmpty()) {
+            System.out.println("[DEBUG] 第一条数据: " + page.getList().get(0).getPointName());
+        }
+        model.addAttribute("page", page);
+        return "modules/WorkKnowledgeBase/workKnowledgeBasePointRuleList";
+    }
+
+    /** 新增/编辑表单 */
+    @RequiresPermissions(value = {"workKnowledgeBase:pointRule:add", "workKnowledgeBase:pointRule:edit"}, logical = org.apache.shiro.authz.annotation.Logical.OR)
+    @RequestMapping(value = "form")
+    public String form(WorkKnowledgeBasePointRule workKnowledgeBasePointRule, Model model) {
+        if (workKnowledgeBasePointRule.getStatus() == null) {
+            workKnowledgeBasePointRule.setStatus(1);
+        }
+        model.addAttribute("workKnowledgeBasePointRule", workKnowledgeBasePointRule);
+        return "modules/WorkKnowledgeBase/workKnowledgeBasePointRuleForm";
+    }
+
+    /** 保存(标准 form submit,非 AJAX) */
+    @RequiresPermissions(value = {"workKnowledgeBase:pointRule:add", "workKnowledgeBase:pointRule:edit"}, logical = org.apache.shiro.authz.annotation.Logical.OR)
+    @RequestMapping(value = "save")
+    public String save(WorkKnowledgeBasePointRule workKnowledgeBasePointRule, Model model, RedirectAttributes redirectAttributes) {
+        String err = pointRuleService.saveRule(workKnowledgeBasePointRule);
+        if (err != null) {
+            addMessage(model, err);
+            model.addAttribute("workKnowledgeBasePointRule", workKnowledgeBasePointRule);
+            return "modules/WorkKnowledgeBase/workKnowledgeBasePointRuleForm";
+        }
+        addMessage(redirectAttributes, "保存积分规则成功");
+        return "redirect:"+ Global.getAdminPath()+"/workKnowledgeBase/pointRule/?repage";
+    }
+
+    /** 逻辑删除 */
+    @ResponseBody
+    @RequiresPermissions("workKnowledgeBase:pointRule:del")
+    @RequestMapping(value = "delete")
+    public AjaxJson delete(@RequestParam("id") String id) {
+        AjaxJson j = new AjaxJson();
+        pointRuleService.deleteRule(id);
+        j.setSuccess(true);
+        j.setMsg("删除成功");
+        return j;
+    }
+
+    /** 切换状态 status=1 启用 / 0 禁用 */
+    @ResponseBody
+    @RequiresPermissions("workKnowledgeBase:pointRule:edit")
+    @RequestMapping(value = "toggleStatus")
+    public AjaxJson toggleStatus(@RequestParam("id") String id,
+                                 @RequestParam("status") Integer status) {
+        AjaxJson j = new AjaxJson();
+        String err = pointRuleService.toggleStatus(id, status);
+        if (err != null) {
+            j.setSuccess(false);
+            j.setMsg(err);
+        } else {
+            j.setSuccess(true);
+            j.setMsg(status != null && status == 1 ? "已启用" : "已禁用");
+        }
+        return j;
+    }
+}

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

@@ -6,11 +6,13 @@ import com.jeeplus.common.persistence.Page;
 import com.jeeplus.common.utils.StringUtils;
 import com.jeeplus.common.utils.excel.ImportExcel;
 import com.jeeplus.common.web.BaseController;
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseAuditRecord;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicInfo;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseDynamicValueInfo;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseImportInfo;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseShareInfo;
 import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBaseShareService;
+import com.jeeplus.modules.sys.utils.UserUtils;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
@@ -89,6 +91,15 @@ public class WorkKnowledgeBaseShareController extends BaseController {
         if (StringUtils.isNotBlank(rootId)) {
             shareService.findDynamicPage(page, shareInfo, dynamicFields, dynamicConditions);
         }
+        List<Map<String, Object>> list = page.getList();
+        for (Map<String, Object> map : list) {
+            if(UserUtils.getUser().isAdmin()){
+                map.put("isAdmin", true);
+            }else{
+                map.put("isAdmin", false);
+            }
+        }
+
 
         model.addAttribute("page", page);
         model.addAttribute("shareInfo", shareInfo);
@@ -96,6 +107,7 @@ public class WorkKnowledgeBaseShareController extends BaseController {
         model.addAttribute("dynamicConditions", dynamicConditions);
         model.addAttribute("treeNodeId", treeNodeId);
         model.addAttribute("rootId", rootId);
+        model.addAttribute("isAdmin", UserUtils.getUser().isAdmin() || UserUtils.isManager());
         return "modules/WorkKnowledgeBase/workKnowledgeBaseShareList";
     }
 
@@ -140,6 +152,12 @@ public class WorkKnowledgeBaseShareController extends BaseController {
         model.addAttribute("dynamicFields", dynamicFields);
         model.addAttribute("rootId", rootId);
         model.addAttribute("dynValues", dynValues);
+
+        // 加载审核记录(审核中、审核通过、审核未通过状态时展示)
+        String auditStatus = shareInfo.getAuditStatus();
+        if (auditStatus != null && (auditStatus.equals("1") || auditStatus.equals("2") || auditStatus.equals("4") || auditStatus.equals("5"))) {
+            model.addAttribute("auditRecords", shareService.findAuditRecordsByFileId(shareInfo.getId()));
+        }
         return "modules/WorkKnowledgeBase/workKnowledgeBaseShareDetail";
     }
 
@@ -192,6 +210,7 @@ public class WorkKnowledgeBaseShareController extends BaseController {
     /**
      * 保存文件信息(含动态字段值)
      * 动态字段值以 JSON 数组字符串形式提交:dynamicValuesJson
+     * 审核状态根据附件有无自动判定
      */
     @RequiresPermissions(value = {"workKnowledgeBase:share:add", "workKnowledgeBase:share:edit"})
     @RequestMapping(value = "save")
@@ -202,6 +221,22 @@ public class WorkKnowledgeBaseShareController extends BaseController {
             return form(shareInfo, model);
         }
         try {
+            // 审核中(2)和审核通过(5)不允许编辑
+            if (!shareInfo.getIsNewRecord()) {
+                String auditStatus = shareInfo.getAuditStatus();
+                if (auditStatus != null && auditStatus.equals(WorkKnowledgeBaseShareService.AUDIT_STATUS_AUDITING)) {
+                    addMessage(redirectAttributes, "审核中的数据不允许编辑");
+                    return "redirect:" + Global.getAdminPath() + "/workKnowledgeBase/share/list";
+                }
+                if (auditStatus != null && auditStatus.equals(WorkKnowledgeBaseShareService.AUDIT_STATUS_PASSED)) {
+                    // 审核通过仅管理员可编辑
+                    if (!UserUtils.getUser().isAdmin() && !UserUtils.isManager()) {
+                        addMessage(redirectAttributes, "审核通过的数据仅管理员可编辑");
+                        return "redirect:" + Global.getAdminPath() + "/workKnowledgeBase/share/list";
+                    }
+                }
+            }
+
             // 解析动态字段值
             if (StringUtils.isNotBlank(dynamicValuesJson)) {
                 dynamicValuesJson = dynamicValuesJson.replace("&quot;", "\"");
@@ -219,6 +254,7 @@ public class WorkKnowledgeBaseShareController extends BaseController {
 
     /**
      * 删除文件(逻辑删除,Ajax)
+     * 增加审核状态校验:审核中禁止删除,审核通过仅管理员可删除
      */
     @RequiresPermissions("workKnowledgeBase:share:del")
     @RequestMapping(value = "delete")
@@ -226,6 +262,21 @@ public class WorkKnowledgeBaseShareController extends BaseController {
     public Map<String, Object> delete(WorkKnowledgeBaseShareInfo shareInfo) {
         Map<String, Object> result = new HashMap<>();
         try {
+            // 审核中禁止删除
+            String auditStatus = shareInfo.getAuditStatus();
+            if (auditStatus != null && auditStatus.equals(WorkKnowledgeBaseShareService.AUDIT_STATUS_AUDITING)) {
+                result.put("success", false);
+                result.put("message", "审核中的数据不允许删除");
+                return result;
+            }
+            // 审核通过仅管理员可删除
+            if (auditStatus != null && auditStatus.equals(WorkKnowledgeBaseShareService.AUDIT_STATUS_PASSED)) {
+                if (!UserUtils.getUser().isAdmin() && !UserUtils.isManager()) {
+                    result.put("success", false);
+                    result.put("message", "审核通过的数据仅管理员可删除");
+                    return result;
+                }
+            }
             shareService.deleteShare(shareInfo);
             result.put("success", true);
             result.put("message", "删除成功");
@@ -278,4 +329,104 @@ public class WorkKnowledgeBaseShareController extends BaseController {
         }
         return result;
     }
+
+    // ======================== 审核相关接口 ========================
+
+    /**
+     * 发起审核(未审核 -> 审核中)
+     */
+    @RequiresPermissions("workKnowledgeBase:share:audit")
+    @RequestMapping(value = "submitAudit")
+    @ResponseBody
+    public Map<String, Object> submitAudit(@RequestParam String id) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            shareService.submitAudit(id);
+            result.put("success", true);
+            result.put("message", "已发起审核");
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 审核通过
+     */
+    @RequiresPermissions("workKnowledgeBase:share:audit")
+    @RequestMapping(value = "auditPass")
+    @ResponseBody
+    public Map<String, Object> auditPass(@RequestParam String id,
+                                         @RequestParam(required = false) String auditOpinion) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            String currentUserId = UserUtils.getUser().getId();
+            shareService.auditPass(id, currentUserId, auditOpinion);
+            result.put("success", true);
+            result.put("message", "审核通过操作成功");
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 审核驳回
+     */
+    @RequiresPermissions("workKnowledgeBase:share:audit")
+    @RequestMapping(value = "auditReject")
+    @ResponseBody
+    public Map<String, Object> auditReject(@RequestParam String id,
+                                           @RequestParam(required = false) String auditOpinion) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            String currentUserId = UserUtils.getUser().getId();
+            shareService.auditReject(id, currentUserId, auditOpinion);
+            result.put("success", true);
+            result.put("message", "审核驳回操作成功");
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 撤回审核(审核中 -> 草稿)
+     */
+    @RequiresPermissions("workKnowledgeBase:share:audit")
+    @RequestMapping(value = "withdrawAudit")
+    @ResponseBody
+    public Map<String, Object> withdrawAudit(@RequestParam String id) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            shareService.withdrawAudit(id);
+            result.put("success", true);
+            result.put("message", "已撤回审核");
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 查询审核记录列表(Ajax)
+     */
+    @RequestMapping(value = "auditRecords")
+    @ResponseBody
+    public Map<String, Object> auditRecords(@RequestParam String fileId) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            List<WorkKnowledgeBaseAuditRecord> records = shareService.findAuditRecordsByFileId(fileId);
+            result.put("success", true);
+            result.put("data", records);
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", e.getMessage());
+        }
+        return result;
+    }
 }

+ 185 - 0
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseAuditRecordDao.xml

@@ -0,0 +1,185 @@
+<?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.WorkKnowledgeBaseAuditRecordDao">
+
+    <sql id="auditRecordColumns">
+        a.id              AS "id",
+        a.file_id         AS "fileId",
+        a.audit_user_id   AS "auditUserId",
+        a.audit_result    AS "auditResult",
+        a.audit_opinion   AS "auditOpinion",
+        a.audit_time      AS "auditTime",
+        a.create_date     AS "createDate",
+        a.del_flag        AS "delFlag"
+    </sql>
+
+    <!-- 单条查询 -->
+    <select id="get" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseAuditRecord">
+        SELECT <include refid="auditRecordColumns"/>
+        FROM work_knowledge_base_audit_record a
+        WHERE a.id = #{id}
+    </select>
+
+    <!-- 根据文件ID查询审核记录列表 -->
+    <select id="findByFileId" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseAuditRecord">
+        SELECT <include refid="auditRecordColumns"/>,
+               (SELECT su.name FROM sys_user su WHERE su.id = a.audit_user_id) AS "auditUserName"
+        FROM work_knowledge_base_audit_record a
+        WHERE a.file_id = #{fileId}
+          AND a.del_flag = '0'
+        ORDER BY a.audit_time DESC
+    </select>
+
+    <!-- 根据文件ID查询本轮审核记录(audit_time >= startTime) -->
+    <select id="findByFileIdSinceTime" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseAuditRecord">
+        SELECT <include refid="auditRecordColumns"/>,
+               (SELECT su.name FROM sys_user su WHERE su.id = a.audit_user_id) AS "auditUserName"
+        FROM work_knowledge_base_audit_record a
+        WHERE a.file_id = #{fileId}
+          AND a.del_flag = '0'
+          <if test="startTime != null">AND a.audit_time &gt;= #{startTime}</if>
+        ORDER BY a.audit_time DESC
+    </select>
+
+    <!-- 检查某用户是否已审核过某文件 -->
+    <select id="countByFileIdAndUserId" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_audit_record a
+        WHERE a.file_id = #{fileId}
+          AND a.audit_user_id = #{auditUserId}
+          AND a.del_flag = '0'
+    </select>
+
+    <!-- 检查某用户本轮是否已审核过某文件 -->
+    <select id="countByFileIdAndUserIdSinceTime" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_audit_record a
+        WHERE a.file_id = #{fileId}
+          AND a.audit_user_id = #{auditUserId}
+          AND a.del_flag = '0'
+          <if test="startTime != null">AND a.audit_time &gt;= #{startTime}</if>
+    </select>
+
+    <!-- 统计某文件的通过审核数 -->
+    <select id="countPassByFileId" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_audit_record a
+        WHERE a.file_id = #{fileId}
+          AND a.audit_result = 1
+          AND a.del_flag = '0'
+    </select>
+
+    <!-- 统计某文件本轮的通过审核数 -->
+    <select id="countPassByFileIdSinceTime" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_audit_record a
+        WHERE a.file_id = #{fileId}
+          AND a.audit_result = 1
+          AND a.del_flag = '0'
+          <if test="startTime != null">AND a.audit_time &gt;= #{startTime}</if>
+    </select>
+
+    <!-- 统计某文件的驳回审核数 -->
+    <select id="countRejectByFileId" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_audit_record a
+        WHERE a.file_id = #{fileId}
+          AND a.audit_result = 2
+          AND a.del_flag = '0'
+    </select>
+
+    <!-- 统计某文件本轮的驳回审核数 -->
+    <select id="countRejectByFileIdSinceTime" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_audit_record a
+        WHERE a.file_id = #{fileId}
+          AND a.audit_result = 2
+          AND a.del_flag = '0'
+          <if test="startTime != null">AND a.audit_time &gt;= #{startTime}</if>
+    </select>
+
+    <!-- 批量查询指定用户已审核过的文件ID列表(仅本轮审核) -->
+    <select id="findAuditedFileIdsByUserId" resultType="java.lang.String">
+        SELECT DISTINCT a.file_id
+        FROM work_knowledge_base_audit_record a
+        INNER JOIN work_knowledge_base_share_info s ON s.id = a.file_id
+        WHERE a.audit_user_id = #{userId}
+          AND a.del_flag = '0'
+          AND (s.audit_start_date IS NULL OR a.audit_time &gt;= s.audit_start_date)
+    </select>
+
+    <select id="findList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseAuditRecord">
+        SELECT <include refid="auditRecordColumns"/>
+        FROM work_knowledge_base_audit_record a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.audit_time DESC
+    </select>
+
+    <select id="findListByUser" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseAuditRecord">
+        SELECT <include refid="auditRecordColumns"/>
+        FROM work_knowledge_base_audit_record a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.audit_time DESC
+    </select>
+
+    <select id="findAllList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseAuditRecord">
+        SELECT <include refid="auditRecordColumns"/>
+        FROM work_knowledge_base_audit_record a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.audit_time DESC
+    </select>
+
+    <select id="findUniqueByProperty" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseAuditRecord">
+        SELECT <include refid="auditRecordColumns"/>
+        FROM work_knowledge_base_audit_record a
+        WHERE ${propertyName} = #{value} AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <select id="queryCount" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_audit_record a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+    </select>
+
+    <!-- 插入 -->
+    <insert id="insert">
+        INSERT INTO work_knowledge_base_audit_record (
+            id, file_id, audit_user_id, audit_result, audit_opinion, audit_time,
+            create_date, del_flag
+        ) VALUES (
+            #{id}, #{fileId}, #{auditUserId}, #{auditResult}, #{auditOpinion}, #{auditTime},
+            #{createDate}, #{delFlag}
+        )
+    </insert>
+
+    <!-- 更新 -->
+    <update id="update">
+        UPDATE work_knowledge_base_audit_record SET
+            audit_result  = #{auditResult},
+            audit_opinion = #{auditOpinion},
+            audit_time    = #{auditTime}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 物理删除 -->
+    <delete id="delete">
+        DELETE FROM work_knowledge_base_audit_record WHERE id = #{id}
+    </delete>
+
+    <!-- 逻辑删除 -->
+    <update id="deleteByLogic">
+        UPDATE work_knowledge_base_audit_record SET
+            del_flag = #{DEL_FLAG_DELETE}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 根据文件ID逻辑删除所有审核记录(撤回/驳回时作废历史记录) -->
+    <update id="logicDeleteByFileId">
+        UPDATE work_knowledge_base_audit_record SET
+            del_flag = '1'
+        WHERE file_id = #{fileId}
+          AND del_flag = '0'
+    </update>
+
+</mapper>

+ 206 - 0
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBasePointDetailDao.xml

@@ -0,0 +1,206 @@
+<?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.WorkKnowledgeBasePointDetailDao">
+
+    <sql id="pointDetailColumns">
+        a.id            AS "id",
+        a.user_id       AS "userId",
+        a.share_id      AS "shareId",
+        a.change_type   AS "changeType",
+        a.point         AS "point",
+        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.WorkKnowledgeBasePointDetail">
+        SELECT <include refid="pointDetailColumns"/>
+        FROM work_knowledge_base_point_detail a
+        WHERE a.id = #{id}
+    </select>
+
+    <select id="findList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointDetail">
+        SELECT <include refid="pointDetailColumns"/>
+        FROM work_knowledge_base_point_detail a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.create_date DESC
+    </select>
+
+    <select id="findListByUser" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointDetail">
+        SELECT <include refid="pointDetailColumns"/>
+        FROM work_knowledge_base_point_detail a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.create_date DESC
+    </select>
+
+    <select id="findAllList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointDetail">
+        SELECT <include refid="pointDetailColumns"/>
+        FROM work_knowledge_base_point_detail a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.create_date DESC
+    </select>
+
+    <select id="findUniqueByProperty" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointDetail">
+        SELECT <include refid="pointDetailColumns"/>
+        FROM work_knowledge_base_point_detail a
+        WHERE ${propertyName} = #{value} AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <select id="queryCount" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_point_detail a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+    </select>
+
+    <insert id="insert">
+        INSERT INTO work_knowledge_base_point_detail (
+            id, user_id, share_id, change_type, point,
+            create_by, create_date, update_by, update_date, remarks, del_flag
+        ) VALUES (
+            #{id}, #{userId}, #{shareId}, #{changeType}, #{point},
+            #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks}, #{delFlag}
+        )
+    </insert>
+
+    <update id="update">
+        UPDATE work_knowledge_base_point_detail SET
+            change_type = #{changeType},
+            point       = #{point},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate},
+            remarks     = #{remarks}
+        WHERE id = #{id}
+    </update>
+
+    <delete id="delete">
+        DELETE FROM work_knowledge_base_point_detail WHERE id = #{id}
+    </delete>
+
+    <update id="deleteByLogic">
+        UPDATE work_knowledge_base_point_detail SET
+            del_flag = #{DEL_FLAG_DELETE}
+        WHERE id = #{id}
+    </update>
+
+    <!-- ============================================================
+         用户积分汇总查询(列表页)
+         输出字段:userId/userName/officeName/mobile/phone/totalPoint
+         仅返回存在积分记录的用户
+         参数:userName(姓名模糊)/officeName(部门模糊)/offset/limit
+         ============================================================ -->
+    <select id="findUserPointSummaryList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.UserPointSummary">
+        SELECT
+            u.id        AS "userId",
+            u.name      AS "userName",
+            u.mobile    AS "mobile",
+            u.phone     AS "phone",
+            o.name      AS "officeName",
+            COALESCE(SUM(d.point), 0) AS "totalPoint"
+        FROM sys_user u
+        INNER JOIN work_knowledge_base_point_detail d ON d.user_id = u.id AND d.del_flag = '0'
+        LEFT JOIN sys_office o ON o.id = u.office_id
+        <where>
+            u.del_flag = '0'
+            <if test="userName != null and userName != ''">
+                AND u.name LIKE CONCAT('%', #{userName}, '%')
+            </if>
+            <if test="officeIdList != null and officeIdList.size() > 0">
+                AND u.office_id IN
+                <foreach collection="officeIdList" item="officeId" open="(" separator="," close=")">
+                    #{officeId}
+                </foreach>
+            </if>
+        </where>
+        GROUP BY u.id, u.name, u.mobile, u.phone, o.name
+        ORDER BY totalPoint DESC, u.name ASC
+        <if test="offset != null and limit != null">
+            LIMIT #{offset}, #{limit}
+        </if>
+    </select>
+
+    <select id="findUserPointSummaryCount" resultType="java.lang.Integer">
+        SELECT COUNT(1) FROM (
+            SELECT u.id
+            FROM sys_user u
+            INNER JOIN work_knowledge_base_point_detail d ON d.user_id = u.id AND d.del_flag = '0'
+            LEFT JOIN sys_office o ON o.id = u.office_id
+            <where>
+                u.del_flag = '0'
+                <if test="userName != null and userName != ''">
+                    AND u.name LIKE CONCAT('%', #{userName}, '%')
+                </if>
+                <if test="officeName != null and officeName != ''">
+                    AND o.name LIKE CONCAT('%', #{officeName}, '%')
+                </if>
+            </where>
+            GROUP BY u.id
+        ) t
+    </select>
+
+    <!-- ============================================================
+         用户积分明细查询(子页)
+         输出字段:id/shareId/shareName/treeNodeId/changeType/point/createDate
+         参数:userId(必传)/shareName(文档名模糊)/changeType/beginDate/endDate/offset/limit
+         ============================================================ -->
+    <select id="findUserPointDetailList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.UserPointDetail">
+        SELECT
+            d.id          AS "id",
+            d.user_id     AS "userId",
+            IFNULL(d.share_id, '')  AS "shareId",
+            CAST(d.change_type AS SIGNED) AS "changeType",
+            CAST(IFNULL(d.point, 0) AS SIGNED) AS "point",
+            d.create_date AS "createDate",
+            IFNULL(s.name, '')          AS "shareName",
+            IFNULL(s.tree_node_id, '')  AS "treeNodeId",
+            IFNULL(s.del_flag, '1')     AS "shareDelFlag"
+        FROM work_knowledge_base_point_detail d
+        LEFT JOIN work_knowledge_base_share_info s ON s.id = d.share_id
+        <where>
+            d.del_flag = '0'
+            AND d.user_id = #{userId}
+            <if test="shareName != null and shareName != ''">
+                AND s.name LIKE CONCAT('%', #{shareName}, '%')
+            </if>
+            <if test="changeType != null">
+                AND d.change_type = #{changeType}
+            </if>
+            <if test="beginDate != null and beginDate != ''">
+                AND d.create_date &gt;= #{beginDate}
+            </if>
+            <if test="endDate != null and endDate != ''">
+                AND d.create_date &lt;= CONCAT(#{endDate}, ' 23:59:59')
+            </if>
+        </where>
+        ORDER BY d.create_date DESC
+        <if test="offset != null and limit != null">
+            LIMIT #{offset}, #{limit}
+        </if>
+    </select>
+
+    <select id="findUserPointDetailCount" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_point_detail d
+        LEFT JOIN work_knowledge_base_share_info s ON s.id = d.share_id
+        <where>
+            d.del_flag = '0'
+            AND d.user_id = #{userId}
+            <if test="shareName != null and shareName != ''">
+                AND s.name LIKE CONCAT('%', #{shareName}, '%')
+            </if>
+            <if test="changeType != null">
+                AND d.change_type = #{changeType}
+            </if>
+            <if test="beginDate != null and beginDate != ''">
+                AND d.create_date &gt;= #{beginDate}
+            </if>
+            <if test="endDate != null and endDate != ''">
+                AND d.create_date &lt;= CONCAT(#{endDate}, ' 23:59:59')
+            </if>
+        </where>
+    </select>
+
+</mapper>

+ 150 - 0
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBasePointRuleDao.xml

@@ -0,0 +1,150 @@
+<?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.WorkKnowledgeBasePointRuleDao">
+
+    <sql id="pointRuleColumns">
+        a.id           AS "id",
+        a.rule_type    AS "ruleType",
+        a.point_value  AS "pointValue",
+        a.point_name   AS "pointName",
+        a.status       AS "status",
+        a.create_by    AS "createBy.id",
+        a.create_date  AS "createDate",
+        a.update_by    AS "updateBy.id",
+        a.update_date  AS "updateDate",
+        a.del_flag     AS "delFlag"
+    </sql>
+
+    <select id="get" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointRule">
+        SELECT <include refid="pointRuleColumns"/>
+        FROM work_knowledge_base_point_rule a
+        WHERE a.id = #{id}
+    </select>
+
+    <select id="findByRuleType" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointRule">
+        SELECT <include refid="pointRuleColumns"/>
+        FROM work_knowledge_base_point_rule a
+        WHERE a.rule_type = #{ruleType}
+          AND a.status = 1
+          AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <select id="findList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointRule">
+        SELECT <include refid="pointRuleColumns"/>,
+            u.name AS "createBy.name"
+        FROM work_knowledge_base_point_rule a
+        LEFT JOIN sys_user u ON u.id = a.create_by
+        <where>
+            a.del_flag = #{DEL_FLAG_NORMAL}
+            <if test="pointName != null and pointName != ''">
+                AND a.point_name LIKE CONCAT('%', #{pointName}, '%')
+            </if>
+            <if test="status != null">
+                AND a.status = #{status}
+            </if>
+        </where>
+        ORDER BY a.update_date DESC
+    </select>
+
+    <select id="findListByUser" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointRule">
+        SELECT <include refid="pointRuleColumns"/>,
+            u.name AS "createBy.name"
+        FROM work_knowledge_base_point_rule a
+        LEFT JOIN sys_user u ON u.id = a.create_by
+        <where>
+            a.del_flag = #{DEL_FLAG_NORMAL}
+            <if test="pointName != null and pointName != ''">
+                AND a.point_name LIKE CONCAT('%', #{pointName}, '%')
+            </if>
+            <if test="status != null">
+                AND a.status = #{status}
+            </if>
+        </where>
+        ORDER BY a.update_date DESC
+    </select>
+
+    <select id="findAllList" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointRule">
+        SELECT <include refid="pointRuleColumns"/>
+        FROM work_knowledge_base_point_rule a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.update_date DESC
+    </select>
+
+    <select id="findUniqueByProperty" resultType="com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointRule">
+        SELECT <include refid="pointRuleColumns"/>
+        FROM work_knowledge_base_point_rule a
+        WHERE ${propertyName} = #{value} AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <select id="queryCount" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_point_rule a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+    </select>
+
+    <insert id="insert">
+        INSERT INTO work_knowledge_base_point_rule (
+            id, rule_type, point_value, point_name, status, create_by, create_date, update_by, update_date, del_flag
+        ) VALUES (
+            #{id}, #{ruleType}, #{pointValue}, #{pointName}, #{status}, #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{delFlag}
+        )
+    </insert>
+
+    <update id="update">
+        UPDATE work_knowledge_base_point_rule SET
+            rule_type   = #{ruleType},
+            point_value = #{pointValue},
+            point_name  = #{pointName},
+            status      = #{status},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE id = #{id}
+    </update>
+
+    <delete id="delete">
+        DELETE FROM work_knowledge_base_point_rule WHERE id = #{id}
+    </delete>
+
+    <update id="deleteByLogic">
+        UPDATE work_knowledge_base_point_rule SET
+            del_flag = #{DEL_FLAG_DELETE}
+        WHERE id = #{id}
+    </update>
+
+    <!-- ============================================================
+         以下为配置管理页专用查询(已废弃,用 findList 替代)
+         ============================================================ -->
+
+    <select id="countEnabledByRuleType" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_point_rule a
+        WHERE a.del_flag = '0'
+          AND a.status = 1
+          AND a.rule_type = #{ruleType}
+        <if test="excludeId != null and excludeId != ''">
+            AND a.id &lt;&gt; #{excludeId}
+        </if>
+    </select>
+
+    <select id="countEnabledByPointName" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_knowledge_base_point_rule a
+        WHERE a.del_flag = '0'
+          AND a.status = 1
+          AND a.point_name = #{pointName}
+        <if test="excludeId != null and excludeId != ''">
+            AND a.id &lt;&gt; #{excludeId}
+        </if>
+    </select>
+
+    <update id="updateStatus">
+        UPDATE work_knowledge_base_point_rule
+        SET status      = #{status},
+            update_by   = #{updateBy},
+            update_date = NOW()
+        WHERE id = #{id}
+    </update>
+
+</mapper>

+ 56 - 27
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseShareInfoDao.xml

@@ -3,18 +3,23 @@
 <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.name      AS "name",
-        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"
+        a.id               AS "id",
+        a.tree_node_id     AS "treeNodeId",
+        a.file_name        AS "fileName",
+        a.file_url         AS "fileUrl",
+        a.name             AS "name",
+        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.audit_status     AS "auditStatus",
+        a.audit_pass_count AS "auditPassCount",
+        a.audit_reject_count AS "auditRejectCount",
+        a.submit_audit_user_id AS "submitAuditUserId",
+        a.audit_start_date AS "auditStartDate",
+        a.del_flag         AS "delFlag"
     </sql>
 
     <!-- 单条查询 -->
@@ -37,7 +42,7 @@
                 AND a.file_name LIKE CONCAT('%',#{fileName},'%')
             </if>
         </where>
-        ORDER BY a.create_date DESC
+        ORDER BY a.update_date DESC
     </select>
 
     <!-- 根据节点id查询文件列表 -->
@@ -66,9 +71,14 @@
             a.name AS "name",
             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",
+            (SELECT su.name FROM sys_user su WHERE su.id = COALESCE(a.submit_audit_user_id, a.create_by)) AS "createByName",
+            a.submit_audit_user_id                                AS "submitAuditUserId",
             a.create_date                                         AS "createDate",
             a.remarks                                             AS "remarks",
+            a.audit_status                                        AS "auditStatus",
+            a.audit_pass_count                                    AS "auditPassCount",
+            a.audit_reject_count                                  AS "auditRejectCount",
+            a.audit_start_date                                    AS "auditStartDate",
             su.name                                               AS "createBy.name"
             <!-- 动态列:CASE WHEN + MAX + GROUP BY -->
             <if test="dynamicFields != null and dynamicFields.size() > 0">
@@ -126,9 +136,9 @@
                 </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
+        GROUP BY a.id, a.tree_node_id, a.file_name, a.file_url, a.name, a.create_time,
+                 a.create_by, a.create_date, a.remarks, a.audit_status, a.audit_pass_count, a.audit_reject_count, a.submit_audit_user_id, a.audit_start_date
+        ORDER BY a.update_date DESC
         <if test="offset != null and limit != null">
             LIMIT #{offset}, #{limit}
         </if>
@@ -199,14 +209,14 @@
         SELECT <include refid="shareColumns"/>
         FROM work_knowledge_base_share_info a
         WHERE a.del_flag = #{DEL_FLAG_NORMAL}
-        ORDER BY a.create_date DESC
+        ORDER BY a.update_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
+        ORDER BY a.update_date DESC
     </select>
 
     <select id="queryCount" resultType="java.lang.Integer">
@@ -219,22 +229,29 @@
     <insert id="insert">
         INSERT INTO work_knowledge_base_share_info (
             id, tree_node_id, file_name, file_url, name, create_time,
-            create_by, create_date, update_by, update_date, remarks, del_flag
+            create_by, create_date, update_by, update_date, remarks,
+            audit_status, audit_pass_count, audit_reject_count, submit_audit_user_id, audit_start_date, del_flag
         ) VALUES (
             #{id}, #{treeNodeId}, #{fileName}, #{fileUrl}, #{name}, NOW(),
-            #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks}, #{delFlag}
+            #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks},
+            #{auditStatus}, #{auditPassCount}, #{auditRejectCount}, #{submitAuditUserId}, #{auditStartDate}, #{delFlag}
         )
     </insert>
 
     <!-- 更新 -->
     <update id="update">
         UPDATE work_knowledge_base_share_info SET
-            file_name   = #{fileName},
-            file_url    = #{fileUrl},
-            name    = #{name},
-            update_by   = #{updateBy.id},
-            update_date = #{updateDate},
-            remarks     = #{remarks}
+            file_name          = #{fileName},
+            file_url           = #{fileUrl},
+            name               = #{name},
+            update_by          = #{updateBy.id},
+            update_date        = #{updateDate},
+            remarks            = #{remarks},
+            audit_status       = #{auditStatus},
+            audit_pass_count   = #{auditPassCount},
+            audit_reject_count = #{auditRejectCount},
+            submit_audit_user_id = #{submitAuditUserId},
+            audit_start_date   = #{auditStartDate}
         WHERE id = #{id}
     </update>
 
@@ -252,4 +269,16 @@
         WHERE id = #{id}
     </update>
 
+    <!-- 只更新审核状态及审核统计字段 -->
+    <update id="updateAuditStatus">
+        UPDATE work_knowledge_base_share_info SET
+            audit_status       = #{auditStatus},
+            audit_pass_count   = #{auditPassCount},
+            audit_reject_count = #{auditRejectCount},
+            audit_start_date   = #{auditStartDate},
+            update_by          = #{updateBy.id},
+            update_date        = #{updateDate}
+        WHERE id = #{id}
+    </update>
+
 </mapper>

+ 2 - 1
src/main/webapp/WEB-INF/tags/table/singleAttachmentManager.tag

@@ -206,12 +206,13 @@
 
                             <%-- 删除按钮(仅上传者可见) --%>
                             <c:if test="${attach.createBy.id eq fns:getUser().id}">
+
+                            </c:if>
                                 <a href="javascript:void(0)"
                                    onclick="deleteFileFromAliyun(this,'${pageContext.request.contextPath}${fns:getAdminPath()}/sys/workattachment/deleteFileFromAliyun?url=${attach.url}&id=${attach.id}&type=2','addFile')"
                                    class="op-btn op-btn-delete">
                                     <i class="fa fa-trash"></i>&nbsp;删除
                                 </a>
-                            </c:if>
                         </div>
                     </td>
                 </tr>

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

@@ -945,6 +945,27 @@ function getAuditLeaveState(id)
     }
     return result;
 }
+
+function getWorkKnowledgeAuditState(id)
+{
+    var result ={};
+    result.action = true;
+    switch(id)
+    {
+        case "0":result.label = "tempstore";result.status="草稿";result.action = false;break;
+        case "1":result.label = "tempstore";result.status="未审核";result.action = false;break;
+        case "2":result.label = "auditing";result.status="审核中";break;
+        case "3":result.label = "cancel";result.status="撤回";break;
+        case "4":result.label = "reject";result.status="审核未通过";break;
+        case "5":result.label = "signed";result.status="审核通过";break;
+        default:
+            result.label = "unknown";result.status="未知";break;
+    }
+    return result;
+}
+
+
+
 /*消除list页面table出现的滚动条,默认二个按钮,130px*/
 function resizeListTable(width){
     var fwidth = width || 130;

+ 86 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBasePointRuleForm.jsp

@@ -0,0 +1,86 @@
+<%@ 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()) {
+                $("#inputForm").submit();
+                return true;
+            }
+            return false;
+        }
+
+        $(document).ready(function() {
+            layui.use(['form', 'layer'], function () {
+                var form = layui.form;
+                form.render();
+            });
+            validateForm = $("#inputForm").validate({
+                submitHandler: function(form) {
+                    loading('正在提交,请稍等...');
+                    form.submit();
+                },
+                errorContainer: "#messageBox",
+                errorPlacement: function(error, element) {
+                    $("#messageBox").text("输入有误,请先更正。");
+                    if (element.is(":checkbox") || element.is(":radio") || element.parent().is(".input-append")) {
+                        error.appendTo(element.parent().parent());
+                    } else {
+                        error.insertAfter(element);
+                    }
+                }
+            });
+        });
+    </script>
+</head>
+<body>
+<div class="single-form">
+    <div class="container">
+        <form:form id="inputForm" modelAttribute="workKnowledgeBasePointRule" action="${ctx}/workKnowledgeBase/pointRule/save" method="post" class="form-horizontal layui-form">
+            <form:hidden path="id"/>
+
+            <div class="form-group layui-row first">
+                <div class="form-group-label"><h2>积分规则信息</h2></div>
+
+                <div class="layui-item layui-col-sm8 lw6">
+                    <label class="layui-form-label"><span class="require-item">*</span>规则名称:</label>
+                    <div class="layui-input-block">
+                        <form:input path="pointName" placeholder="请输入规则名称" htmlEscape="false" maxlength="100" class="form-control layui-input required"/>
+                    </div>
+                </div>
+
+                <div class="layui-item layui-col-sm8 lw6">
+                    <label class="layui-form-label"><span class="require-item">*</span>积分值:</label>
+                    <div class="layui-input-block">
+                        <form:input path="pointValue" placeholder="请输入非负整数" htmlEscape="false" maxlength="10" class="form-control layui-input required digits"/>
+                    </div>
+                </div>
+
+                <div class="layui-item layui-col-sm8 lw6">
+                    <label class="layui-form-label">状态:</label>
+                    <div class="layui-input-block" style="display:flex; align-items:center; height:38px;">
+                        <label style="display:inline-flex; align-items:center; margin-right:30px; cursor:pointer;">
+                            <input type="radio" name="status" value="1" style="margin-right:5px;" ${workKnowledgeBasePointRule.status == 1 || workKnowledgeBasePointRule.status == null ? 'checked' : ''}/> 启用
+                        </label>
+                        <label style="display:inline-flex; align-items:center; cursor:pointer;">
+                            <input type="radio" name="status" value="0" style="margin-right:5px;" ${workKnowledgeBasePointRule.status == 0 ? 'checked' : ''}/> 禁用
+                        </label>
+                    </div>
+                </div>
+
+
+            </div>
+
+            <div class="form-group layui-row page-end"></div>
+        </form:form>
+    </div>
+</div>
+</body>
+</html>

+ 241 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBasePointRuleList.jsp

@@ -0,0 +1,241 @@
+<%@ 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}/ckeditor/ckeditor.js"></script>
+	<script type="text/javascript">
+
+        $(document).ready(function() {
+        });
+
+        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]; //得到iframe页的窗口对象,执行iframe页的方法:iframeWin.method();
+					var inputForm = body.find('#inputForm');
+					var top_iframe;
+					if(target){
+						top_iframe = target;//如果指定了iframe,则在改frame中跳转
+					}else{
+						top_iframe = top.getActiveTab().attr("name");//获取当前active的tab的iframe
+					}
+					inputForm.attr("target",top_iframe);//表单提交成功后,从服务器返回的url在当前tab中展示
+					if(iframeWin.contentWindow.doSubmit(1) ){
+						// top.layer.close(index);//关闭对话框。
+						setTimeout(function(){top.layer.close(index)}, 100);//延时0.1秒,对应360 7.1版本bug
+					}
+				},
+                btn2: function (index) {
+                }
+            });
+        }
+
+        // 删除
+        function deleteInfo(title, id) {
+            layer.open({
+                title: title,
+                maxmin: true,
+                content: '确认要删除该积分规则吗?',
+                skin: 'two-btns',
+                btn: ['确定', '取消'],
+                btn1: function (index, layero) {
+                    $.ajax({
+                        type: "post",
+                        url: "${ctx}/workKnowledgeBase/pointRule/delete?id=" + id,
+                        success: function (data) {
+                            if (data.success) {
+                                parent.layer.msg('删除成功', {icon: 1});
+                                layer.close(index);
+                                window.location.reload();
+                            } else {
+                                parent.layer.msg(data.msg || '删除失败', {icon: 0});
+                                layer.close(index);
+                            }
+                        }
+                    })
+                },
+                btn2: function (index) {
+                }
+            });
+        }
+
+        // 切换状态
+        function toggleStatus(title, id, status) {
+            var msg = (status === 1 ? '确定启用此积分规则吗?' : '确定禁用此积分规则吗?');
+            layer.open({
+                title: title,
+                maxmin: true,
+                content: msg,
+                skin: 'two-btns',
+                btn: ['确定', '取消'],
+                btn1: function (index, layero) {
+                    $.ajax({
+                        type: "post",
+                        url: "${ctx}/workKnowledgeBase/pointRule/toggleStatus",
+                        data: {id: id, status: status},
+                        success: function (data) {
+                            if (data.success) {
+                                parent.layer.msg(data.msg || '操作成功', {icon: 1});
+                                layer.close(index);
+                                window.location.reload();
+                            } else {
+                                parent.layer.msg(data.msg || '操作失败', {icon: 0});
+                                layer.close(index);
+                            }
+                        }
+                    })
+                },
+                btn2: function (index) {
+                }
+            });
+        }
+	</script>
+</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:form id="searchForm" modelAttribute="workKnowledgeBasePointRule" action="${ctx}/workKnowledgeBase/pointRule/list" method="post" class="form-inline">
+					<input id="pageNo" name="pageNo" type="hidden" value="${page.pageNo}"/>
+					<input id="pageSize" name="pageSize" type="hidden" value="${page.pageSize}"/>
+					<table:sortColumn id="orderBy" name="orderBy" value="${page.orderBy}" callback="sortOrRefresh();"/>
+					<div class="commonQuery">
+						<div class="layui-item query athird">
+							<label class="layui-form-label">规则名称:</label>
+							<div class="layui-input-block with-icon">
+								<form:input path="pointName" placeholder="规则名称模糊查询" htmlEscape="false" maxlength="100" class="form-control layui-input"/>
+							</div>
+						</div>
+						<div class="layui-item query athird">
+							<label class="layui-form-label">状态:</label>
+							<div class="layui-input-block">
+								<form:select path="status" class="form-control layui-input">
+									<form:option value="" label="全部"/>
+									<form:option value="1" label="启用"/>
+									<form:option value="0" label="禁用"/>
+								</form:select>
+							</div>
+						</div>
+
+						<div class="layui-item athird">
+							<div class="input-group">
+								<div class="layui-btn-group search-spacing">
+									<button id="searchQuery" class="layui-btn layui-btn-sm  layui-bg-blue" onclick="search()">查询</button>
+									<button id="searchReset" class="layui-btn layui-btn-sm  " onclick="resetSearch()">重置</button>
+								</div>
+							</div>
+						</div>
+						<div style="clear:both;"></div>
+					</div>
+					<div id="moresees" style="clear:both;display:none;">
+						<div style="clear:both;"></div>
+					</div>
+				</form:form>
+			</div>
+		</div>
+		<div class="full-width fl">
+			<div class="contentShadow layui-form contentDetails">
+				<div class="nav-btns">
+					<div class="layui-btn-group">
+						<shiro:hasPermission name="workKnowledgeBase:pointRule:add">
+							<table:addRow label="新增积分规则" url="${ctx}/workKnowledgeBase/pointRule/form" title="新增积分规则" height="400px" width="800px"></table:addRow>
+						</shiro:hasPermission>
+						<button class="layui-btn layui-btn-sm" data-toggle="tooltip" data-placement="left" onclick="sortOrRefresh()" title="刷新"> 刷新</button>
+					</div>
+				</div>
+				<table class="oa-table layui-table" id="contentTable"></table>
+
+				<!-- 分页代码 -->
+				<table:page page="${page}"></table:page>
+				<div style="clear: both;"></div>
+			</div>
+		</div>
+	</div>
+	<div id="changewidth"></div>
+</div>
+<script src="${ctxStatic}/layer-v2.3/layui/layui.all.js" charset="utf-8"></script>
+<script>
+    layui.use('table', function () {
+        layui.table.render({
+            limit: ${ page.pageSize }
+            , id: "checkboxTable"
+            , elem: '#contentTable'
+            , page: false
+            , cols: [[
+                {field: 'index', align: 'center', width: 40, title: '序号'}
+                , {field: 'pointName', align: 'center', title: '规则名称', minWidth: 200}
+                , {field: 'pointValue', align: 'center', title: '积分值', width: 120, templet: function (d) {
+                    return '<span style="color:#1aa094;font-weight:bold;">' + (d.pointValue || 0) + ' 分</span>';
+                }}
+                , {field: 'status', align: 'center', title: '状态', width: 100, templet: function (d) {
+                    var st = parseInt(d.status);
+                    if (st === 1) return '<span class="layui-badge layui-bg-green">启用</span>';
+                    return '<span class="layui-badge layui-bg-gray">禁用</span>';
+                }}
+                , {field: 'createName', align: 'center', title: '创建人', width: 120}
+                , {field: 'updateDate', align: 'center', title: '最后修改时间', width: 160}
+                , {align: 'center', title: "操作", width: 240, templet: function (d) {
+                    var xml = "<div class=\"layui-btn-group\">";
+                    <shiro:hasPermission name="workKnowledgeBase:pointRule:edit">
+                    xml += "<a href=\"javascript:void(0)\" onclick=\"openDialog('修改积分规则', '${ctx}/workKnowledgeBase/pointRule/form?id=" + d.id + "','800px', '400px')\" class=\"layui-btn layui-btn-xs  layui-bg-green\"> 修改</a>";
+                    var st = parseInt(d.status);
+                    if (st === 1) {
+                        xml += "<a href=\"javascript:void(0)\" onclick=\"toggleStatus('禁用规则', '" + d.id + "', 0)\" class=\"layui-btn layui-btn-xs  layui-bg-orange\"> 禁用</a>";
+                    } else {
+                        xml += "<a href=\"javascript:void(0)\" onclick=\"toggleStatus('启用规则', '" + d.id + "', 1)\" class=\"layui-btn layui-btn-xs  layui-bg-cyan\"> 启用</a>";
+                    }
+                    </shiro:hasPermission>
+                    <shiro:hasPermission name="workKnowledgeBase:pointRule:del">
+                    xml += "<a href=\"javascript:void(0)\" onclick=\"deleteInfo('删除',  '" + d.id + "')\" class=\"layui-btn layui-btn-xs layui-bg-red\"> 删除</a>";
+                    </shiro:hasPermission>
+                    xml += "</div>"
+                    return xml;
+                }}
+            ]]
+            ,data: [
+                <c:if test="${not empty page.list}">
+                <c:forEach items="${page.list}" var="workKnowledgeBasePointRule" varStatus="index">
+                <c:if test="${index.index != 0}">,</c:if>
+                {
+                    "index":"${index.index + 1 + (page.pageNo - 1) * page.pageSize}"
+                    ,"id":"${workKnowledgeBasePointRule.id}"
+                    ,"pointName":"<c:out value='${workKnowledgeBasePointRule.pointName}'/>"
+                    ,"pointValue":"${workKnowledgeBasePointRule.pointValue}"
+                    ,"status":"${workKnowledgeBasePointRule.status}"
+                    ,"createName":"<c:out value='${workKnowledgeBasePointRule.createBy.name}'/>"
+                    ,"updateDate":"<fmt:formatDate value='${workKnowledgeBasePointRule.updateDate}' pattern='yyyy-MM-dd HH:mm:ss'/>"
+                }
+                </c:forEach>
+                </c:if>
+            ]
+        });
+
+    })
+
+    resizeListTable();
+</script>
+<script>
+    resizeListWindow1();
+    $(window).resize(function () {
+        resizeListWindow1();
+    });
+</script>
+</body>
+</html>

+ 168 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBasePointUserDetail.jsp

@@ -0,0 +1,168 @@
+<%@ 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">
+        $(document).ready(function() {
+            // 日期选择器
+            layui.use('laydate', function() {
+                var laydate = layui.laydate;
+                laydate.render({elem: '#beginDate', event: 'focus', type: 'date', format: 'yyyy-MM-dd', trigger: 'click'});
+                laydate.render({elem: '#endDate', event: 'focus', type: 'date', format: 'yyyy-MM-dd', trigger: 'click'});
+            });
+
+            // 表格渲染
+            layui.use('table', function() {
+                layui.table.render({
+                    limit: ${page.pageSize},
+                    id: 'pointDetailTable',
+                    elem: '#contentTable',
+                    page: false,
+                    cols: [[
+                        {field: 'index', align: 'center', width: 60, title: '序号'},
+                        {field: 'shareName', align: 'center', title: '积分来源(文档名称)', minWidth: 240, templet: function(d) {
+                            var nm = d.shareName || '';
+                            var sid = d.shareId || '';
+                            // 文档已被删除(物理或逻辑)
+                            if (!sid) {
+                                return '<span style="color:#999;">(无关联文档)</span>';
+                            }
+                            if (d.shareDelFlag === '1' || !nm) {
+                                return '<span style="color:#999;">' + (nm || '(已删除文档)') + '</span>';
+                            }
+                            return '<a href="javascript:void(0)" class="attention-info" onclick="openShareDetail(\'' + sid + '\',\'' + (d.treeNodeId || '') + '\')">' + nm + '</a>';
+                        }},
+                        {field: 'changeType', align: 'center', title: '获取方式', width: 110, templet: function(d) {
+                            var ct = parseInt(d.changeType);
+                            if (ct === 1) return '<span class="layui-badge layui-bg-blue">创建</span>';
+                            if (ct === 2) return '<span class="layui-badge layui-bg-green">审核</span>';
+                            return '';
+                        }},
+                        {field: 'point', align: 'center', title: '积分额度', width: 100, templet: function(d) {
+                            return '<span style="color:#1aa094;font-weight:bold;">+' + (d.point || 0) + '</span>';
+                        }},
+                        {field: 'createDate', align: 'center', title: '时间', width: 170}
+                    ]],
+                    data: [
+                        <c:choose>
+                            <c:when test="${not empty page.list}">
+                                <c:forEach items="${page.list}" var="row" varStatus="st">
+                                    <c:if test="${st.index != 0}">,</c:if>
+                                    {
+                                        "index": "${st.index + 1 + (page.pageNo - 1) * page.pageSize}"
+                                        ,"id": "${row.id}"
+                                        ,"shareId": "${row.shareId}"
+                                        ,"shareName": "<c:out value='${row.shareName}'/>"
+                                        ,"treeNodeId": "${row.treeNodeId}"
+                                        ,"shareDelFlag": "${row.shareDelFlag}"
+                                        ,"changeType": "${row.changeType}"
+                                        ,"point": "${row.point}"
+                                        ,"createDate": "${row.createDate}"
+                                    }
+                                </c:forEach>
+                            </c:when>
+                            <c:otherwise></c:otherwise>
+                        </c:choose>
+                    ]
+                });
+            });
+        });
+
+        /** 跳转到文档详情 */
+        function openShareDetail(shareId, treeNodeId) {
+            top.layer.open({
+                type: 2,
+                area: ['80%', '80%'],
+                title: '文件详情',
+                maxmin: true,
+                content: '${ctx}/workKnowledgeBase/share/detail?id=' + shareId + (treeNodeId ? '&treeNodeId=' + treeNodeId : ''),
+                btn: ['关闭'],
+                btn1: function(index) { top.layer.close(index); }
+            });
+        }
+
+        function search() { $('#searchForm').submit(); return false; }
+        function resetSearch() {
+            $('#searchForm input[type=text]').val('');
+            $('#searchForm select').val('');
+            $('#searchForm').submit();
+        }
+
+        resizeListWindow1 = function() {
+            var height = $(window).height() - 10;
+            $('body').css('min-height', height + 'px');
+        };
+        $(window).resize(function() { resizeListWindow1(); });
+    </script>
+</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/point/userDetail" method="post" class="form-inline">
+                    <input type="hidden" name="userId" value="${userId}"/>
+                    <input type="hidden" name="userName" value="${userName}"/>
+                    <input id="pageNo" name="pageNo" type="hidden" value="${page.pageNo}"/>
+                    <input id="pageSize" name="pageSize" type="hidden" value="${page.pageSize}"/>
+                    <div class="commonQuery lw7">
+                        <div class="layui-item query athird" style="width: 25%">
+                            <label class="layui-form-label">积分来源:</label>
+                            <div class="layui-input-block with-icon">
+                                <input type="text" name="shareName" value="${shareName}"
+                                       placeholder="文档名模糊查询" class="form-control layui-input"/>
+                            </div>
+                        </div>
+                        <div class="layui-item query athird" style="width: 25%">
+                            <label class="layui-form-label">获取方式:</label>
+                            <div class="layui-input-block">
+                                <select name="changeType" class="form-control layui-input">
+                                    <option value="">全部</option>
+                                    <option value="1" ${changeType == 1 ? 'selected' : ''}>创建</option>
+                                    <option value="2" ${changeType == 2 ? 'selected' : ''}>审核</option>
+                                </select>
+                            </div>
+                        </div>
+                        <div class="layui-item query athird" style="width: 25%">
+                            <label class="layui-form-label">时间区间:</label>
+                            <div class="layui-input-block readOnlyFFF with-icon">
+                                <input id="beginDate" placeholder="开始时间" name="beginDate" type="text" readonly="readonly"
+                                       maxlength="20" class="laydate-icondate form-control layer-date layui-input laydate-icon query-group"
+                                       value="${beginDate}"/>
+                                <span class="group-sep">-</span>
+                                <input id="endDate" placeholder="结束时间" name="endDate" type="text" readonly="readonly"
+                                       maxlength="20" class="laydate-icondate form-control layer-date layui-input laydate-icon query-group"
+                                       value="${endDate}"/>
+                            </div>
+                        </div>
+                        <div class="layui-item athird" style="width: 25%">
+                            <div class="input-group">
+                                <div class="layui-btn-group search-spacing">
+                                    <button id="searchQuery" class="layui-btn layui-btn-sm layui-bg-blue" onclick="return search()">查询</button>
+                                    <button id="searchReset" 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">
+                <table class="oa-table layui-table" id="contentTable"></table>
+                <table:page page="${page}"></table:page>
+                <div style="clear:both;"></div>
+            </div>
+        </div>
+    </div>
+</div>
+</body>
+</html>

+ 145 - 0
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBasePointUserList.jsp

@@ -0,0 +1,145 @@
+<%@ 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">
+
+        /** 打开用户积分明细子页 */
+        function openUserDetailDialog(userId, userName) {
+            top.layer.open({
+                type: 2,
+                area: ['85%', '80%'],
+                title: (userName || '用户') + ' - 积分明细',
+                maxmin: true,
+                content: '${ctx}/workKnowledgeBase/point/userDetail?userId=' + userId + '&userName=' + encodeURIComponent(userName || ''),
+                btn: ['关闭'],
+                btn1: function(index) { top.layer.close(index); }
+            });
+        }
+
+        /** 查询/重置 */
+        function search() { 
+            $("#toflag").val("1");
+            $('#searchForm').submit(); 
+            return false; 
+        }
+        function resetSearch() {
+            $("#toflag").val("");
+            $('#searchForm input[type=text]').val('');
+            $('#searchForm select').val('');
+            $('#searchForm').submit();
+        }
+
+        resizeListWindow1 = function() {
+            var height = $(window).height() - 10;
+            $('body').css('min-height', height + 'px');
+        };
+        $(window).resize(function() { resizeListWindow1(); });
+        
+        function blurSubmitterId(obj) {
+            // 经办人输入框失去焦点时的处理函数
+            // 这里可以添加对经办人输入的验证或处理逻辑
+            // 目前留空,仅作为占位符
+        }
+    </script>
+</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/point/userList" method="post" class="form-inline">
+                    <input id="pageNo" name="pageNo" type="hidden" value="${page.pageNo}"/>
+                    <input id="pageSize" name="pageSize" type="hidden" value="${page.pageSize}"/>
+                    <input id="toflag" name="toflag" type="hidden" value="${workKnowledgeBasePointQuery.toflag}"/>
+                    <input id="userName" name="userName" type="hidden" value="${workKnowledgeBasePointQuery.userName}"/>
+                    <input id="officeId" name="officeId" type="hidden" value="${workKnowledgeBasePointQuery.officeId}"/>
+                    <div class="commonQuery lw7">
+                        <div class="layui-item query athird">
+                            <label class="layui-form-label">经办人:</label>
+                            <div class="layui-input-block with-icon">
+                                <input type="text" name="workKnowledgeBasePointQuery.userName" value="${workKnowledgeBasePointQuery.userName}"
+                                       placeholder="经办人模糊查询" class="form-control layui-input" onblur="blurSubmitterId(this)"/>
+                            </div>
+                        </div>
+                        <div class="layui-item query athird">
+                            <label class="layui-form-label">经办人部门:</label>
+                            <div class="layui-input-block with-icon">
+                                <sys:treeselect id="officeId" name="workKnowledgeBasePointQuery.officeId" value="${workKnowledgeBasePointQuery.officeId}" labelName="officeName" labelValue="${officeName}" cssStyle="background-color: #fff"
+                                                title="部门" url="/sys/office/treeDataAll?type=6" cssClass="form-control layui-input" allowInput="true" allowClear="true" notAllowSelectParent="true" />
+                            </div>
+                        </div>
+                        <div class="layui-item athird">
+                            <div class="input-group">
+                                <div class="layui-btn-group search-spacing">
+                                    <button id="searchQuery" class="layui-btn layui-btn-sm layui-bg-blue" onclick="return search()">查询</button>
+                                    <button id="searchReset" 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">
+                <table class="oa-table layui-table" id="contentTable"></table>
+                <table:page page="${page}"></table:page>
+                <div style="clear:both;"></div>
+            </div>
+        </div>
+    </div>
+</div>
+<script src="${ctxStatic}/layer-v2.3/layui/layui.all.js" charset="utf-8"></script>
+<script>
+    layui.use('table', function(){
+        layui.table.render({
+            limit:${ page.pageSize }
+            ,elem: '#contentTable'
+            ,page: false
+            ,cols: [[
+                {field:'index',align:'center', title: '序号',width:40}
+                ,{field:'userName', align: 'center', title: '经办人', minWidth: 120, templet: function(d) {
+                    var name = d.userName || '';
+                    return '<a href="javascript:void(0)" class="attention-info" onclick="openUserDetailDialog(\'' + d.userId + '\',\'' + name.replace(/'/g, "\\'") + '\')">' + name + '</a>';
+                }}
+                ,{field:'officeName', align: 'center', title: '经办人部门', minWidth: 160}
+                ,{field:'mobile', align: 'center', title: '手机号', minWidth: 130, templet: function(d) {
+                    return d.mobile || d.phone || '';
+                }}
+                ,{field:'totalPoint', align: 'center', title: '积分数量', width: 110, templet: function(d) {
+                    return '<span style="color:#1aa094;font-weight:bold;">' + (d.totalPoint || 0) + '</span>';
+                }}
+            ]]
+            ,data: [
+                <c:choose>
+                    <c:when test="${not empty page.list}">
+                        <c:forEach items="${page.list}" var="row" varStatus="st">
+                            <c:if test="${st.index != 0}">,</c:if>
+                            {
+                                "index": "${st.index + 1 + (page.pageNo - 1) * page.pageSize}"
+                                ,"userId": "${row.userId}"
+                                ,"userName": "<c:out value='${row.userName}'/>"
+                                ,"officeName": "<c:out value='${row.officeName}'/>"
+                                ,"mobile": "<c:out value='${row.mobile}'/>"
+                                ,"phone": "<c:out value='${row.phone}'/>"
+                                ,"totalPoint": "${row.totalPoint}"
+                            }
+                        </c:forEach>
+                    </c:when>
+                    <c:otherwise></c:otherwise>
+                </c:choose>
+            ]
+        });
+    });
+</script>
+</body>
+</html>

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

@@ -10,6 +10,43 @@
         .detail-label { font-weight: bold; color: #555; }
         .detail-value { color: #333; word-break: break-all; }
     </style>
+    <script type="text/javascript">
+        /** 供父页面弹窗按钮回调 */
+        function doSubmit(obj) {
+            var opinion = $('#auditOpinion').val();
+            if (obj == 1) {
+                // 通过:审核意见为空时默认"同意"
+                if (!opinion || opinion.trim() === '') {
+                    opinion = '同意';
+                }
+                var url = '${ctx}/workKnowledgeBase/share/auditPass';
+            } else {
+                // 驳回:审核意见为空时默认"驳回"
+                if (!opinion || opinion.trim() === '') {
+                    opinion = '驳回';
+                }
+                var url = '${ctx}/workKnowledgeBase/share/auditReject';
+            }
+            var success = false;
+            $.ajax({
+                type: 'POST',
+                url: url,
+                async: false,
+                data: { id: '${entity.id}', auditOpinion: opinion },
+                success: function(data) {
+                    if (data.success) {
+                        success = true;
+                    } else {
+                        top.layer.msg(data.message || '操作失败', {icon: 2});
+                    }
+                },
+                error: function() {
+                    top.layer.msg('请求失败,请重试', {icon: 2});
+                }
+            });
+            return success;
+        }
+    </script>
 </head>
 <body>
 <div class="single-form">
@@ -28,6 +65,52 @@
             </div>
         </div>
 
+        <!-- 审核状态 -->
+        <div class="form-group layui-row">
+            <div class="layui-item layui-col-sm6 lw6">
+                <label class="layui-form-label detail-label">审核状态:</label>
+                <div class="layui-input-block">
+                    <c:set var="auditStatusVal" value="${entity.auditStatus != null ? entity.auditStatus : 0}"/>
+                    <c:set var="auditStatusName">
+                        <c:choose>
+                            <c:when test="${auditStatusVal == 0}">草稿</c:when>
+                            <c:when test="${auditStatusVal == 1}">未审核</c:when>
+                            <c:when test="${auditStatusVal == 2}">审核中</c:when>
+                            <c:when test="${auditStatusVal == 4}">审核未通过</c:when>
+                            <c:when test="${auditStatusVal == 5}">审核通过</c:when>
+                            <c:otherwise>未知</c:otherwise>
+                        </c:choose>
+                    </c:set>
+                    <c:set var="auditStatusColor">
+                        <c:choose>
+                            <c:when test="${auditStatusVal == 0}">gray</c:when>
+                            <c:when test="${auditStatusVal == 1}">#E6A23C</c:when>
+                            <c:when test="${auditStatusVal == 2}">#409EFF</c:when>
+                            <c:when test="${auditStatusVal == 4}">#F56C6C</c:when>
+                            <c:when test="${auditStatusVal == 5}">#67C23A</c:when>
+                            <c:otherwise>gray</c:otherwise>
+                        </c:choose>
+                    </c:set>
+                    <input type="text" class="form-control layui-input" value="${auditStatusName}" readonly="readonly"
+                           style="color:${auditStatusColor};font-weight:bold;"/>
+                </div>
+            </div>
+            <c:if test="${auditStatusVal == 2 || auditStatusVal == 4 || auditStatusVal == 5}">
+            <div class="layui-item layui-col-sm3 lw6">
+                <label class="layui-form-label detail-label">通过人数:</label>
+                <div class="layui-input-block">
+                    <input type="text" class="form-control layui-input" value="${entity.auditPassCount != null ? entity.auditPassCount : 0}" readonly="readonly"/>
+                </div>
+            </div>
+            <div class="layui-item layui-col-sm3 lw6">
+                <label class="layui-form-label detail-label">驳回人数:</label>
+                <div class="layui-input-block">
+                    <input type="text" class="form-control layui-input" value="${entity.auditRejectCount != null ? entity.auditRejectCount : 0}" readonly="readonly"/>
+                </div>
+            </div>
+            </c:if>
+        </div>
+
         <!-- 动态扩展字段(只读展示) -->
         <c:if test="${not empty dynamicFields}">
             <div class="form-group layui-row">
@@ -120,8 +203,72 @@
             </div>
         </c:if>
 
+
+        <!-- 审核意见区域(审核中和未审核状态下,非创建人可见) -->
+        <c:set var="auditStatusInt" value="${entity.auditStatus != null ? entity.auditStatus : 0}"/>
+        <c:set var="isCreator" value="${entity.createBy != null && entity.createBy.id == fns:getUser().id}"/>
+        <c:if test="${(auditStatusInt == 1 || auditStatusInt == 2) && !isCreator}">
+            <div class="form-group layui-row">
+                <div class="form-group-label"><h2>审核意见</h2></div>
+                <div class="layui-item layui-col-sm12 lw6 with-textarea">
+                    <label class="layui-form-label">审核意见:</label>
+                    <div class="layui-input-block">
+                    <textarea id="auditOpinion" class="form-control" rows="4" maxlength="500"
+                              placeholder="通过时默认为'同意',驳回时默认为'驳回'"></textarea>
+                    </div>
+                </div>
+            </div>
+        </c:if>
+
         <div class="form-group layui-row page-end"></div>
     </div>
+
 </div>
+
+
+
+<!-- 审核记录(审核中和审核通过/未通过时展示) -->
+<c:if test="${auditStatusInt == 1 || auditStatusInt == 2 || auditStatusInt == 4 || auditStatusInt == 5}">
+<div class="single-form" style="margin-top:10px;">
+    <div class="container">
+        <div class="form-group layui-row">
+            <div class="form-group-label"><h2>审核记录</h2></div>
+            <div class="layui-item layui-col-xs12" style="padding:0 16px;">
+                <table class="table table-bordered table-condensed details">
+                    <thead>
+                    <tr>
+                        <th>审核人</th>
+                        <th>审核时间</th>
+                        <th>审核结果</th>
+                        <th>审核意见</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <c:forEach items="${auditRecords}" var="record">
+                        <tr>
+                            <td>${record.auditUserName}</td>
+                            <td><fmt:formatDate value="${record.auditTime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
+                            <td>
+                                <c:choose>
+                                    <c:when test="${record.auditResult == 1}"><span style="color:green">通过</span></c:when>
+                                    <c:when test="${record.auditResult == 2}"><span style="color:red">驳回</span></c:when>
+                                    <c:otherwise>-</c:otherwise>
+                                </c:choose>
+                            </td>
+                            <td>${record.auditOpinion != null && record.auditOpinion != '' ? record.auditOpinion : '-'}</td>
+                        </tr>
+                    </c:forEach>
+                    <c:if test="${empty auditRecords}">
+                        <tr><td colspan="4" style="text-align:center;color:#999;">暂无审核记录</td></tr>
+                    </c:if>
+                    </tbody>
+                </table>
+            </div>
+        </div>
+    </div>
+</div>
+</c:if>
+
+
 </body>
 </html>

+ 228 - 6
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareList.jsp

@@ -85,6 +85,41 @@
             });
         }
 
+        /** 审核详情弹窗(三按钮:通过/驳回/关闭) */
+        function openAuditDetailDialog(id) {
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {
+                var width = 'auto'; var height = 'auto';
+            } else {
+                var width = '80%'; var height = '80%';
+            }
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: '审核详情',
+                skin: 'three-btns',
+                maxmin: true,
+                content: '${ctx}/workKnowledgeBase/share/detail?id=' + id + '&treeNodeId=${treeNodeId}&rootId=${rootId}',
+                btn: ['通过', '驳回', '关闭'],
+                btn1: function(index, layero) {
+                    var iframeWin = layero.find('iframe')[0];
+                    if (iframeWin.contentWindow.doSubmit(1)) {
+                        top.layer.close(index);
+                        setTimeout(function(){ search(); }, 100);
+                    }
+                },
+                btn2: function(index, layero) {
+                    var iframeWin = layero.find('iframe')[0];
+                    if (iframeWin.contentWindow.doSubmit(2)) {
+                        top.layer.close(index);
+                        setTimeout(function(){ search(); }, 100);
+                    }
+                    return false;
+                },
+                btn3: function(index) {
+                }
+            });
+        }
+
         /** 删除文件 */
         function deleteShare(id) {
             layer.open({
@@ -111,11 +146,156 @@
             });
         }
 
+        /** 发起审核 */
+        function submitAudit(id) {
+            layer.open({
+                title: '发起审核确认',
+                content: '确认要对该数据发起审核吗?发起后将进入审核流程。',
+                skin: 'two-btns',
+                btn: ['确定', '取消'],
+                btn1: function(index) {
+                    $.ajax({
+                        type: 'POST',
+                        url: '${ctx}/workKnowledgeBase/share/submitAudit?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 openAuditDialog(id, action) {
+            var title = action === 'pass' ? '审核通过' : '审核驳回';
+            var html = '<div style="padding:15px;">'
+                + '<div style="margin-bottom:10px;"><label>审核意见(选填,最多500字):</label></div>'
+                + '<textarea id="auditOpinionInput" maxlength="500" rows="4" style="width:100%;resize:vertical;" placeholder="请输入审核意见"></textarea>'
+                + '</div>';
+            layer.open({
+                type: 1,
+                title: title,
+                area: ['450px', '280px'],
+                content: html,
+                btn: ['确认', '取消'],
+                btn1: function(index) {
+                    var opinion = $('#auditOpinionInput').val();
+                    var url = action === 'pass'
+                        ? '${ctx}/workKnowledgeBase/share/auditPass?id=' + id
+                        : '${ctx}/workKnowledgeBase/share/auditReject?id=' + id;
+                    $.ajax({
+                        type: 'POST',
+                        url: url,
+                        data: { auditOpinion: opinion },
+                        success: function(data) {
+                            if (data.success) {
+                                layer.msg(title + '操作成功', {icon: 1});
+                                layer.close(index);
+                                search();
+                            } else {
+                                layer.msg(data.message || '操作失败', {icon: 0});
+                            }
+                        }
+                    });
+                },
+                btn2: function(index) { layer.close(index); }
+            });
+        }
+
+        /** 撤回审核 */
+        function withdrawAudit(id) {
+            layer.open({
+                title: '撤回审核确认',
+                content: '确认要撤回审核吗?撤回后状态将变更为草稿。',
+                skin: 'two-btns',
+                btn: ['确定', '取消'],
+                btn1: function(index) {
+                    $.ajax({
+                        type: 'POST',
+                        url: '${ctx}/workKnowledgeBase/share/withdrawAudit?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 viewAuditRecords(id) {
+            $.ajax({
+                type: 'GET',
+                url: '${ctx}/workKnowledgeBase/share/auditRecords?fileId=' + id,
+                success: function(data) {
+                    var html = '<div style="padding:10px;">';
+                    if (data.success && data.data && data.data.length > 0) {
+                        html += '<table class="layui-table" style="width:100%;">';
+                        html += '<thead><tr><th>审核人</th><th>审核时间</th><th>审核结果</th><th>审核意见</th></tr></thead><tbody>';
+                        for (var i = 0; i < data.data.length; i++) {
+                            var r = data.data[i];
+                            html += '<tr>';
+                            html += '<td>' + (r.auditUserName || '') + '</td>';
+                            html += '<td>' + (r.auditTime || '') + '</td>';
+                            html += '<td>' + (r.auditResult === 1 ? '<span style="color:green">通过</span>' : '<span style="color:red">驳回</span>') + '</td>';
+                            html += '<td>' + (r.auditOpinion || '-') + '</td>';
+                            html += '</tr>';
+                        }
+                        html += '</tbody></table>';
+                    } else {
+                        html += '<div style="text-align:center;color:#999;padding:20px;">暂无审核记录</div>';
+                    }
+                    html += '</div>';
+                    layer.open({
+                        type: 1,
+                        title: '审核记录',
+                        area: ['700px', '400px'],
+                        content: html,
+                        btn: ['关闭'],
+                        btn1: function(index) { layer.close(index); }
+                    });
+                }
+            });
+        }
+
         /** 查询 */
         function search() {
             $('#searchForm').submit();
         }
 
+        /** 获取审核状态显示配置 */
+        /*function getWorkKnowledgeAuditState(auditStatus) {
+            var statusMap = {0:'草稿', 1:'未审核', 2:'审核中', 4:'审核未通过', 5:'审核通过'};
+            var labelMap = {0:'default', 1:'warning', 2:'primary', 4:'danger', 5:'success'};
+            return {
+                status: statusMap[auditStatus] || '未知',
+                label: labelMap[auditStatus] || 'default'
+            };
+        }*/
+
+        /** 获取审核状态显示配置(label值对应 style.css 中 status-label-xxx 样式) */
+        function getWorkKnowledgeAuditState(auditStatus) {
+            var statusMap = {0:'草稿', 1:'未审核', 2:'审核中', 4:'审核未通过', 5:'审核通过'};
+            var labelMap = {0:'tempstore', 1:'tempstore', 2:'auditing', 4:'reject', 5:'signed'};
+            return {
+                status: statusMap[auditStatus] || '未知',
+                label: labelMap[auditStatus] || 'unknown'
+            };
+        }
+
         /** 导入弹窗 */
         function openImportDialog() {
             top.layer.open({
@@ -306,14 +486,52 @@
             </c:forEach>
             {field: 'createByName', align: 'center', title: '创建人', width: 100},
             {field: 'createTime', align: 'center', title: '创建时间', width: 160},
-            {align: 'center', title: '操作', width: 160, fixed: 'right', templet: function(d) {
+
+            {align:'center', title: '状态', fixed: 'right', width:70,templet:function(d){
+                    var st = getWorkKnowledgeAuditState(parseInt(d.auditStatus));
+                    var xml = "<span onclick=\"openDetailDialog('" + d.id + "')\" class=\"status-label status-label-" + st.label + "\" >" + st.status + "</span>";
+                    return xml;
+                }},
+            {align: 'center', title: '操作', width: 260, fixed: 'right', templet: function(d) {
                 var xml = '<div class="layui-btn-group">';
-                    if(d.canedit != undefined && d.canedit == "1"){
-                        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>';
+                var status = parseInt(d.auditStatus);
+                var isCreator = (d.submitAuditUserId) === d.userid;
+
+                // 草稿0:可修改、删除
+                if (status === 0) {
+                    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>';
+                }
+
+                // 未审核 1/审核中2:撤回(提交审核人/管理员)、查看审核(非提交审核人)
+                if (status === 1 || status === 2) {
+                    // 撤回:提交审核人/管理员
+                    if (isCreator || d.isAdmin) {
+                        xml += '<a href="javascript:void(0)" onclick="withdrawAudit(\'' + d.id + '\')" class="layui-btn layui-btn-xs layui-bg-orange"> 撤回</a>';
                     }
-                    if(d.candelete != undefined && d.candelete == "1"){
-                        xml += '<a href="javascript:void(0)" onclick="deleteShare(\'' + d.id + '\')" class="layui-btn layui-btn-xs layui-bg-red"> 删除</a>';
+                    // 查看/审核:非提交审核人且当前登录人未审核过时才展示审核按钮
+                    if (!isCreator && !d.currentUserAudited) {
+                        xml += '<a href="javascript:void(0)" onclick="openAuditDetailDialog(\'' + d.id + '\')" class="layui-btn layui-btn-xs layui-bg-blue"> 审核</a>';
                     }
+                }
+
+                // 审核未通过4:可修改、删除
+                if (status === 4) {
+                    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>';
+                }
+
+                // 审核通过5:普通用户仅查看,管理员可修改删除
+                if (status === 5 && d.isAdmin) {
+                    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>';
+                }
+
+                // 审核记录按钮(审核中和审核通过/未通过时展示)
+                if (status === 1 || status === 2 || status === 4 || status === 5) {
+                    xml += '<a href="javascript:void(0)" onclick="viewAuditRecords(\'' + d.id + '\')" class="layui-btn layui-btn-xs"> 记录</a>';
+                }
+
                 xml += '</div>';
                 return xml;
             }}
@@ -340,9 +558,12 @@
                     ,"uploadMode": "<c:out value='${row.uploadMode}'/>"
                     ,"fileUrl": "<c:out value='${row.fileUrl}'/>"
                     ,"createTime": "${row.createTime}"
-                    ,"createByName": "${row.createBy.name}"
+                    ,"createByName": "${row.createByName}"
                     ,"userid": "${fns:getUser().id}"
                     ,"createbyid": "${row.createById}"
+                    ,"isAdmin": ${row.isAdmin == 'true' ? 'true' : 'false'}
+                    ,"submitAuditUserId": "${row.submitAuditUserId}"
+                    ,"auditStatus": ${row.auditStatus != null ? row.auditStatus : 0}
                     <c:forEach items="${dynamicFields}" var="field">
                     ,"dynamic_${field.fieldKey}": "<c:out value='${row["dynamic_".concat(field.fieldKey)]}'/>"
 
@@ -351,6 +572,7 @@
                     <shiro:hasPermission name="workKnowledgeBase:share:del">,"candelete":"1"</shiro:hasPermission>
                     </c:if>
                     </c:forEach>
+                    ,"currentUserAudited": ${row.currentUserAudited == true}
                 }
                 </c:forEach>
                 </c:when>