Ver código fonte

论坛功能提交

徐滕 3 dias atrás
pai
commit
40e30f0df2
33 arquivos alterados com 8045 adições e 24 exclusões
  1. 206 0
      src/main/java/com/jeeplus/modules/forum/dao/ForumDao.java
  2. 59 0
      src/main/java/com/jeeplus/modules/forum/dao/ForumDiscussionDao.java
  3. 54 0
      src/main/java/com/jeeplus/modules/forum/dao/ForumRecordDao.java
  4. 425 0
      src/main/java/com/jeeplus/modules/forum/entity/Forum.java
  5. 76 0
      src/main/java/com/jeeplus/modules/forum/entity/ForumComment.java
  6. 89 0
      src/main/java/com/jeeplus/modules/forum/entity/ForumDiscussion.java
  7. 142 0
      src/main/java/com/jeeplus/modules/forum/entity/ForumDiscussionUser.java
  8. 89 0
      src/main/java/com/jeeplus/modules/forum/entity/ForumRecord.java
  9. 60 0
      src/main/java/com/jeeplus/modules/forum/entity/ForumView.java
  10. 1418 0
      src/main/java/com/jeeplus/modules/forum/service/ForumService.java
  11. 1161 0
      src/main/java/com/jeeplus/modules/forum/web/ForumController.java
  12. 1 1
      src/main/java/com/jeeplus/modules/ruralprojectrecords/dao/RuralProjectRecordsDao.java
  13. 3 3
      src/main/java/com/jeeplus/modules/ruralprojectrecords/service/RuralProjectRecordsService.java
  14. 1 1
      src/main/java/com/jeeplus/modules/ruralprojectrecords/web/RuralProjectRecordsController.java
  15. 11 13
      src/main/java/com/jeeplus/modules/workinvoice/web/WorkInvoiceAllController.java
  16. 43 0
      src/main/java/com/jeeplus/modules/workprojectnotify/web/WorkProjectNotifyController.java
  17. 1150 0
      src/main/resources/mappings/modules/forum/ForumDao.xml
  18. 69 0
      src/main/resources/mappings/modules/forum/ForumDiscussionDao.xml
  19. 177 0
      src/main/resources/mappings/modules/forum/ForumRecordDao.xml
  20. 1 1
      src/main/resources/mappings/modules/ruralprojectrecords/RuralProjectRecordsDao.xml
  21. 1 1
      src/main/webapp/WEB-INF/tags/table/importInvoiceBatchExcel.tag
  22. 163 0
      src/main/webapp/webpage/modules/forum/forumAudit.jsp
  23. 428 0
      src/main/webapp/webpage/modules/forum/forumAuditRecordList.jsp
  24. 153 0
      src/main/webapp/webpage/modules/forum/forumDiscussionView.jsp
  25. 157 0
      src/main/webapp/webpage/modules/forum/forumForm.jsp
  26. 652 0
      src/main/webapp/webpage/modules/forum/forumIndex.jsp
  27. 684 0
      src/main/webapp/webpage/modules/forum/forumList.jsp
  28. 210 0
      src/main/webapp/webpage/modules/forum/forumUsersForm.jsp
  29. 357 0
      src/main/webapp/webpage/modules/forum/forumView.jsp
  30. 2 1
      src/main/webapp/webpage/modules/ruralprojectrecords/cost/ruralCostProjectRecordsForm.jsp
  31. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceAllList.jsp
  32. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceAllTwoList.jsp
  33. 1 1
      src/main/webapp/webpage/modules/workinvoice/workInvoiceTwoList.jsp

+ 206 - 0
src/main/java/com/jeeplus/modules/forum/dao/ForumDao.java

@@ -0,0 +1,206 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.modules.forum.dao;
+
+import com.jeeplus.common.persistence.CrudDao;
+import com.jeeplus.common.persistence.annotation.MyBatisDao;
+import com.jeeplus.modules.forum.entity.*;
+import com.jeeplus.modules.sys.entity.User;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 通知通告DAO接口
+ * @author jeeplus
+ * @version 2014-05-16
+ */
+@MyBatisDao
+public interface ForumDao extends CrudDao<Forum> {
+
+	/**
+	 * 获取通知数目
+	 * @param forum
+	 * @return
+	 */
+	public Long findCount(Forum forum);
+
+
+    String getCreateId(String id);
+    void saveRemarks(Forum forum);
+
+
+    //查询全部公告
+    List<Forum> findAll(Forum forum);
+
+
+    //我的通告
+    List<Forum> findListByMyself(Forum forum);
+    //我的通告
+    List<Forum> findListByPc(Forum forum);
+
+    /**
+     * 查询自己创建的论坛中的帖子信息
+     * @param forum
+     * @return
+     */
+    List<Forum> findMyJoinListByPc(Forum forum);
+
+    /**
+     * 查询所有的论坛中的帖子信息
+     * @param forum
+     * @return
+     */
+    List<Forum> findAllListByPc(Forum forum);
+
+    /**
+     * 查询自己创建的论坛中的帖子信息
+     * @param forum
+     * @return
+     */
+    List<Forum> findMyCreateListByPc(Forum forum);
+
+    //我的通告(未过期)
+    List<Forum> findUnReadList(Forum forum);
+
+    //我的通告(已过期)
+    List<Forum> findReadList(Forum forum);
+
+    /**
+     * 根据公告id查询查看公告记录信息
+     * @param forumId
+     * @return
+     */
+    List<ForumView> getForumViewList(String forumId);
+
+    /**
+     * 根据公告id查询查看公告记录信息
+     * @param forumId
+     * @return
+     */
+    List<ForumComment> getForumCommentList(String forumId);
+
+    /**
+     * 根据公告id和用户id查询查看公告信息数据
+     * @param forumId
+     * @param userId
+     * @return
+     */
+    ForumView getForumView(@Param("forumId") String forumId, @Param("userId")String userId);
+
+    /**
+     * 新增公告浏览记录
+     * @param forumView
+     */
+    void saveForumView(ForumView forumView);
+
+    /**
+     * 修改公告浏览记录
+     * @param forumView
+     */
+    void updateForumView(ForumView forumView);
+
+    /**
+     * 根据公告id 新增评论
+     * @param forumComment
+     * @return
+     */
+    int saveComment(ForumComment forumComment);
+
+    /**
+     * 根据评论id 删除评论
+     * @param id 评论ID
+     * @return
+     */
+    int deleteComment(String id);
+
+    /**
+     * 新增论坛信息
+     * @param forumDiscussion
+     * @return
+     */
+    int saveForumDiscussion(ForumDiscussion forumDiscussion);
+
+    /**
+     * 查询论坛信息
+     * @param forumDiscussion
+     * @return
+     */
+    ForumDiscussion getForumDiscussion(ForumDiscussion forumDiscussion);
+
+
+
+
+    //查询全部公告
+    List<ForumDiscussion> getMyForumDiscussionList(ForumDiscussion forumDiscussion);
+
+    //查询全部公告
+    List<ForumDiscussion> getMyJoinForumDiscussionList(ForumDiscussion forumDiscussion);
+
+    //查询全部公告
+    List<ForumDiscussion> getAllForumDiscussionList(ForumDiscussion forumDiscussion);
+
+    /**
+     * 修改论坛信息
+     * @param forumDiscussion
+     * @return
+     */
+    int updateForumDiscussion(ForumDiscussion forumDiscussion);
+
+    /**
+     * 删除论坛信息
+     * @param forumDiscussion
+     * @return
+     */
+    int deleteForumDiscussion(ForumDiscussion forumDiscussion);
+
+
+    List<User> isUserDelFlag(@Param("forumId") String forumId, @Param("delFlag")String delFlag );
+
+    int insertUsers(@Param("forumDiscussionUserList") List<ForumDiscussionUser> forumDiscussionUserList);
+
+    int reInsertUser(ForumDiscussion forumDiscussion);
+
+    int deleteUsers(ForumDiscussionUser forumDiscussion);
+
+    /**
+     * 退出论坛
+     * @param forumDiscussionId
+     * @param userId
+     * @return
+     */
+    int deleteByForumIdAndUserId(@Param("forumDiscussionId") String forumDiscussionId, @Param("userId") String userId);
+
+    /**
+     * 判断是否已经加入该论坛
+     * @param forumDiscussionId
+     * @param userId
+     * @return
+     */
+    int checkForumDiscussionUserExist(@Param("forumDiscussionId") String forumDiscussionId, @Param("userId") String userId);
+
+
+    void updateStatusById(ForumDiscussionUser forumDiscussionUser);
+
+    void updateProcessIdAndStatus(ForumDiscussionUser forumDiscussionUser);
+
+
+
+    /**
+     * 根据id查询用户加入论坛的信息
+     * @param forumDiscussionUser
+     * @return
+     */
+    ForumDiscussionUser getForumDiscussionUserById(ForumDiscussionUser forumDiscussionUser);
+
+
+    /**
+     * 查询自己创建的论坛中的帖子信息
+     * @param forum
+     * @return
+     */
+    List<ForumDiscussionUser> findByForumDiscussionAuditList(ForumDiscussionUser forum);
+
+
+}

+ 59 - 0
src/main/java/com/jeeplus/modules/forum/dao/ForumDiscussionDao.java

@@ -0,0 +1,59 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.modules.forum.dao;
+
+import com.jeeplus.common.persistence.CrudDao;
+import com.jeeplus.common.persistence.annotation.MyBatisDao;
+import com.jeeplus.modules.forum.entity.ForumDiscussion;
+import com.jeeplus.modules.sys.entity.User;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 通知通告DAO接口
+ * @author jeeplus
+ * @version 2014-05-16
+ */
+@MyBatisDao
+public interface ForumDiscussionDao extends CrudDao<ForumDiscussion> {
+
+    /**
+     * 新增论坛信息
+     * @param forumDiscussion
+     * @return
+     */
+    int saveForumDiscussion(ForumDiscussion forumDiscussion);
+
+    /**
+     * 查询论坛信息
+     * @param forumDiscussion
+     * @return
+     */
+    ForumDiscussion getForumDiscussion(ForumDiscussion forumDiscussion);
+
+
+
+
+    //查询全部公告
+    List<ForumDiscussion> getMyForumDiscussionList(ForumDiscussion forumDiscussion);
+
+    /**
+     * 修改论坛信息
+     * @param forumDiscussion
+     * @return
+     */
+    int updateForumDiscussion(ForumDiscussion forumDiscussion);
+
+    /**
+     * 删除论坛信息
+     * @param forumDiscussion
+     * @return
+     */
+    int deleteForumDiscussion(ForumDiscussion forumDiscussion);
+
+
+    public List<User> isUserDelFlag(@Param("forumId") String forumId, @Param("delFlag")String delFlag );
+
+}

+ 54 - 0
src/main/java/com/jeeplus/modules/forum/dao/ForumRecordDao.java

@@ -0,0 +1,54 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.modules.forum.dao;
+
+import com.jeeplus.common.persistence.CrudDao;
+import com.jeeplus.common.persistence.annotation.MyBatisDao;
+import com.jeeplus.modules.forum.entity.ForumRecord;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 通知通告记录DAO接口
+ * @author jeeplus
+ * @version 2014-05-16
+ */
+@MyBatisDao
+public interface ForumRecordDao extends CrudDao<ForumRecord> {
+
+	/**
+	 * 插入通知记录
+	 * @param forumRecordList
+	 * @return
+	 */
+	public int insertAll(List<ForumRecord> forumRecordList);
+	/**
+	 * 插入通知记录
+	 * @param forumRecordOfficeList
+	 * @return
+	 */
+	public int insertOfficeAll(List<ForumRecord> forumRecordOfficeList);
+
+	/**
+	 * 根据通知ID删除通知记录
+	 * @param forumId 通知ID
+	 * @return
+	 */
+	public int deleteByForumId(String forumId);
+
+
+	//PC端使用
+	public List<ForumRecord> findList2(@Param("forumRecord") ForumRecord forumRecord);
+	//PC端使用
+	public List<ForumRecord> findOffices(ForumRecord forumRecord);
+	public List<ForumRecord> findUsers(ForumRecord forumRecord);
+
+
+	 public List<ForumRecord> findUserList(ForumRecord forumRecord);
+}
+
+
+
+

+ 425 - 0
src/main/java/com/jeeplus/modules/forum/entity/Forum.java

@@ -0,0 +1,425 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.modules.forum.entity;
+
+import com.google.common.collect.Lists;
+import com.jeeplus.common.persistence.ActEntity;
+import com.jeeplus.modules.sys.entity.Office;
+import com.jeeplus.modules.sys.entity.User;
+import com.jeeplus.modules.sys.entity.Workattachment;
+import org.hibernate.validator.constraints.Length;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 通知通告Entity
+ * @author jeeplus
+ * @version 2014-05-16
+ */
+public class Forum extends ActEntity<Forum> {
+
+	private static final long serialVersionUID = 1L;
+	private String type;		// 类型
+	private String tabType;		// 类型
+	private String typeStr;		// 类型字符串
+	private String parentType;		// 父类型
+	private String title;		// 标题
+	private String number;      //公告编号
+	private String content;		// 类型
+	private String contents;		// 类型
+	private String files;		// 附件
+	private String status;		// 状态 0-草稿 1-发布
+	private Office company;	// 发公告公司
+	private Office office;	// 发公告部门
+	private Date startDate; //公告开始时间
+	private Date endDate; //公告结束时间
+	private List<User> userList;
+	private List<Office> officeList;
+	private String candel;
+
+	private String readNum;		// 已读
+	private String unReadNum;	// 未读
+
+	private boolean isSelf;		// 是否只查询自己的通知
+
+    private String readFlag;	// 本人阅读状态
+    private String readFlagStr;	// 本人阅读状态
+    private String state;//是否富文本 1是 2不是
+	private List<Workattachment> workAttachments;//附件
+	private Integer ext;//公告状态:0短期,1长期
+	private Date createStartDate;
+	private Date createEndDate;
+	private Date nowDate;
+
+	private String home;
+	private String commentContent;
+
+	private String processInstanceId;
+	private Integer closeStatus;  //关闭状态
+	private String flagAdmin;     //管理员状态(1:管理员,0:非管理员)
+	private String referenceNumber;     //文号
+	private String flagOffice;     //是否为办公室权限(1:是,0:否)
+	private Integer notifyFlag; //代办判定条件
+	private String notifyId; //代办判定条件
+	private String userId; //用户id
+	private String forumDiscussionName; //论坛名称
+	private String forumDiscussionId; //论坛id
+
+
+    public String getHome() {
+        return home;
+    }
+
+    public void setHome(String home) {
+        this.home = home;
+    }
+
+    public String getContents() {
+        return contents;
+    }
+
+    public void setContents(String contents) {
+        this.contents = contents;
+    }
+
+    public String getState() {
+        return state;
+    }
+
+    public void setState(String state) {
+        this.state = state;
+    }
+
+    private List<ForumRecord> forumRecordList = Lists.newArrayList();
+    private List<ForumRecord> forumRecordOfficeList = Lists.newArrayList();
+
+	public Forum() {
+		super();
+	}
+
+	public Forum(String id){
+		super(id);
+	}
+
+	@Length(min=0, max=200, message="标题长度必须介于 0 和 200 之间")
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getType() {
+		return type;
+	}
+
+	public void setType(String type) {
+		this.type = type;
+	}
+
+
+
+	@Length(min=0, max=1, message="状态长度必须介于 0 和 1 之间")
+	public String getStatus() {
+		return status;
+	}
+
+	public void setStatus(String status) {
+		this.status = status;
+	}
+
+	@Length(min=0, max=2000, message="附件长度必须介于 0 和 2000 之间")
+	public String getFiles() {
+		return files;
+	}
+
+	public void setFiles(String files) {
+		this.files = files;
+	}
+
+	public String getContent() {
+		return content;
+	}
+
+	public void setContent(String content) {
+		this.content = content;
+	}
+
+	public String getReadNum() {
+		return readNum;
+	}
+
+	public void setReadNum(String readNum) {
+		this.readNum = readNum;
+	}
+
+	public String getUnReadNum() {
+		return unReadNum;
+	}
+
+	public void setUnReadNum(String unReadNum) {
+		this.unReadNum = unReadNum;
+	}
+
+
+
+	public boolean isSelf() {
+		return isSelf;
+	}
+
+	public void setSelf(boolean isSelf) {
+		this.isSelf = isSelf;
+	}
+
+	public String getReadFlag() {
+		return readFlag;
+	}
+
+	public void setReadFlag(String readFlag) {
+		this.readFlag = readFlag;
+	}
+
+	public Office getCompany() {
+		return company;
+	}
+
+	public void setCompany(Office company) {
+		this.company = company;
+	}
+
+	public Office getOffice() {
+		return office;
+	}
+
+	public void setOffice(Office office) {
+		this.office = office;
+	}
+
+
+	public String getNumber() {
+		return number;
+	}
+
+	public void setNumber(String number) {
+		this.number = number;
+	}
+
+	public Date getStartDate() {
+		return startDate;
+	}
+
+	public void setStartDate(Date startDate) {
+		this.startDate = startDate;
+	}
+
+	public Date getEndDate() {
+		return endDate;
+	}
+
+	public void setEndDate(Date endDate) {
+		this.endDate = endDate;
+	}
+
+	public List<User> getUserList() {
+		return userList;
+	}
+
+	public void setUserList(List<User> userList) {
+		this.userList = userList;
+	}
+
+	public List<Office> getOfficeList() {
+		return officeList;
+	}
+
+	public void setOfficeList(List<Office> officeList) {
+		this.officeList = officeList;
+	}
+
+	public List<Workattachment> getWorkAttachments() {
+		return workAttachments;
+	}
+
+	public void setWorkAttachments(List<Workattachment> workAttachments) {
+		this.workAttachments = workAttachments;
+	}
+
+	public String getCandel() {
+		return candel;
+	}
+
+	public void setCandel(String candel) {
+		this.candel = candel;
+	}
+
+	public Date getCreateStartDate() {
+		return createStartDate;
+	}
+
+	public void setCreateStartDate(Date createStartDate) {
+		this.createStartDate = createStartDate;
+	}
+
+	public Date getCreateEndDate() {
+		return createEndDate;
+	}
+
+	public void setCreateEndDate(Date createEndDate) {
+		this.createEndDate = createEndDate;
+	}
+
+	public Date getNowDate() {
+		return nowDate;
+	}
+
+	public void setNowDate(Date nowDate) {
+		this.nowDate = nowDate;
+	}
+
+    public String getProcessInstanceId() {
+        return processInstanceId;
+    }
+
+    public void setProcessInstanceId(String processInstanceId) {
+        this.processInstanceId = processInstanceId;
+    }
+
+	public Integer getCloseStatus() {
+		return closeStatus;
+	}
+
+	public void setCloseStatus(Integer closeStatus) {
+		this.closeStatus = closeStatus;
+	}
+
+	public String getFlagAdmin() {
+		return flagAdmin;
+	}
+
+	public void setFlagAdmin(String flagAdmin) {
+		this.flagAdmin = flagAdmin;
+	}
+
+	public String getReferenceNumber() {
+		return referenceNumber;
+	}
+
+	public void setReferenceNumber(String referenceNumber) {
+		this.referenceNumber = referenceNumber;
+	}
+
+	public String getReadFlagStr() {
+		return readFlagStr;
+	}
+
+	public void setReadFlagStr(String readFlagStr) {
+		this.readFlagStr = readFlagStr;
+	}
+
+	public String getFlagOffice() {
+		return flagOffice;
+	}
+
+	public void setFlagOffice(String flagOffice) {
+		this.flagOffice = flagOffice;
+	}
+
+	public Integer getNotifyFlag() {
+		return notifyFlag;
+	}
+
+	public void setNotifyFlag(Integer notifyFlag) {
+		this.notifyFlag = notifyFlag;
+	}
+
+	public String getNotifyId() {
+		return notifyId;
+	}
+
+	public void setNotifyId(String notifyId) {
+		this.notifyId = notifyId;
+	}
+
+	public Integer getExt() {
+		return ext;
+	}
+
+	public void setExt(Integer ext) {
+		this.ext = ext;
+	}
+
+	public String getCommentContent() {
+		return commentContent;
+	}
+
+	public void setCommentContent(String commentContent) {
+		this.commentContent = commentContent;
+	}
+
+	public String getTypeStr() {
+		return typeStr;
+	}
+
+	public void setTypeStr(String typeStr) {
+		this.typeStr = typeStr;
+	}
+
+	public String getParentType() {
+		return parentType;
+	}
+
+	public void setParentType(String parentType) {
+		this.parentType = parentType;
+	}
+
+	public List<ForumRecord> getForumRecordList() {
+		return forumRecordList;
+	}
+
+	public void setForumRecordList(List<ForumRecord> forumRecordList) {
+		this.forumRecordList = forumRecordList;
+	}
+
+	public List<ForumRecord> getForumRecordOfficeList() {
+		return forumRecordOfficeList;
+	}
+
+	public void setForumRecordOfficeList(List<ForumRecord> forumRecordOfficeList) {
+		this.forumRecordOfficeList = forumRecordOfficeList;
+	}
+
+	public String getTabType() {
+		return tabType;
+	}
+
+	public void setTabType(String tabType) {
+		this.tabType = tabType;
+	}
+
+	public String getUserId() {
+		return userId;
+	}
+
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+
+	public String getForumDiscussionName() {
+		return forumDiscussionName;
+	}
+
+	public void setForumDiscussionName(String forumDiscussionName) {
+		this.forumDiscussionName = forumDiscussionName;
+	}
+
+	public String getForumDiscussionId() {
+		return forumDiscussionId;
+	}
+
+	public void setForumDiscussionId(String forumDiscussionId) {
+		this.forumDiscussionId = forumDiscussionId;
+	}
+}

+ 76 - 0
src/main/java/com/jeeplus/modules/forum/entity/ForumComment.java

@@ -0,0 +1,76 @@
+package com.jeeplus.modules.forum.entity;
+
+
+import com.jeeplus.common.persistence.DataEntity;
+import com.jeeplus.modules.sys.entity.User;
+
+/**
+ * 公告评论表
+ * @author: 徐滕
+ * @create: 2021-05-07 11:13
+ **/
+public class ForumComment extends DataEntity<ForumComment> {
+    private Integer count;      //评论总量
+    private String forumId;  //公告id
+    private String content;     //评论内容
+    private User user;          //评论人
+    private Long minuteTime;          //评论时间距今相差分钟数
+    private String commentDateStr;     //评论时间
+    private Integer flag;       //判断是否有删除权限
+
+    public Integer getCount() {
+        return count;
+    }
+
+    public void setCount(Integer count) {
+        this.count = count;
+    }
+
+    public String getForumId() {
+        return forumId;
+    }
+
+    public void setForumId(String forumId) {
+        this.forumId = forumId;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    public String getCommentDateStr() {
+        return commentDateStr;
+    }
+
+    public void setCommentDateStr(String commentDateStr) {
+        this.commentDateStr = commentDateStr;
+    }
+
+    public Long getMinuteTime() {
+        return minuteTime;
+    }
+
+    public void setMinuteTime(Long minuteTime) {
+        this.minuteTime = minuteTime;
+    }
+
+    public Integer getFlag() {
+        return flag;
+    }
+
+    public void setFlag(Integer flag) {
+        this.flag = flag;
+    }
+}

+ 89 - 0
src/main/java/com/jeeplus/modules/forum/entity/ForumDiscussion.java

@@ -0,0 +1,89 @@
+package com.jeeplus.modules.forum.entity;
+
+
+import com.jeeplus.common.persistence.DataEntity;
+import com.jeeplus.modules.sys.entity.User;
+
+import java.util.List;
+
+/**
+ * 论坛表
+ * @author: 徐滕
+ * @create: 2021-05-07 11:13
+ **/
+public class ForumDiscussion extends DataEntity<ForumDiscussion> {
+    private String name;  //论坛名称
+
+
+    private String userIds;
+    private String delUserIds;
+    private String memberNameStr;
+    private String memberIds;
+    private String userId;
+    private List<User> users;
+    private List<ForumDiscussionUser> forumDiscussionUserList;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getUserIds() {
+        return userIds;
+    }
+
+    public void setUserIds(String userIds) {
+        this.userIds = userIds;
+    }
+
+    public String getDelUserIds() {
+        return delUserIds;
+    }
+
+    public void setDelUserIds(String delUserIds) {
+        this.delUserIds = delUserIds;
+    }
+
+    public String getMemberNameStr() {
+        return memberNameStr;
+    }
+
+    public void setMemberNameStr(String memberNameStr) {
+        this.memberNameStr = memberNameStr;
+    }
+
+    public String getMemberIds() {
+        return memberIds;
+    }
+
+    public void setMemberIds(String memberIds) {
+        this.memberIds = memberIds;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public List<User> getUsers() {
+        return users;
+    }
+
+    public void setUsers(List<User> users) {
+        this.users = users;
+    }
+
+    public List<ForumDiscussionUser> getForumDiscussionUserList() {
+        return forumDiscussionUserList;
+    }
+
+    public void setForumDiscussionUserList(List<ForumDiscussionUser> forumDiscussionUserList) {
+        this.forumDiscussionUserList = forumDiscussionUserList;
+    }
+}

+ 142 - 0
src/main/java/com/jeeplus/modules/forum/entity/ForumDiscussionUser.java

@@ -0,0 +1,142 @@
+package com.jeeplus.modules.forum.entity;
+
+
+import com.jeeplus.common.persistence.ActEntity;
+import com.jeeplus.modules.sys.entity.Office;
+
+import java.util.Date;
+
+/**
+ * 论坛组员表
+ * @author: 徐滕
+ * @create: 2021-05-07 11:13
+ **/
+public class ForumDiscussionUser extends ActEntity<ForumDiscussionUser> {
+    private String forumId;  //论坛id
+    private String userId;  //论坛组员id
+    private String userName;  //论坛组员id
+    private String groupType;  //进组类型(自行添加/邀请添加[0/1])
+    private Date groupDate; //进组时间
+    private String processInstanceId; //申请流程id
+    private String status; //申请流程状态
+    private String forumDiscussionName; //论坛名称
+    private String forumDiscussionCreateByName; //论坛创建人名称
+    private Date forumDiscussionCreateDate; //论坛创建的时间
+    private Office company;	// 发公告公司
+    private Office office;	// 发公告部门
+    private String officeName;	// 部门名称
+
+    private String home;
+
+    public String getForumId() {
+        return forumId;
+    }
+
+    public void setForumId(String forumId) {
+        this.forumId = forumId;
+    }
+
+    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 getGroupType() {
+        return groupType;
+    }
+
+    public void setGroupType(String groupType) {
+        this.groupType = groupType;
+    }
+
+    public Date getGroupDate() {
+        return groupDate;
+    }
+
+    public void setGroupDate(Date groupDate) {
+        this.groupDate = groupDate;
+    }
+
+    public String getProcessInstanceId() {
+        return processInstanceId;
+    }
+
+    public void setProcessInstanceId(String processInstanceId) {
+        this.processInstanceId = processInstanceId;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getForumDiscussionName() {
+        return forumDiscussionName;
+    }
+
+    public void setForumDiscussionName(String forumDiscussionName) {
+        this.forumDiscussionName = forumDiscussionName;
+    }
+
+    public Office getCompany() {
+        return company;
+    }
+
+    public void setCompany(Office company) {
+        this.company = company;
+    }
+
+    public Office getOffice() {
+        return office;
+    }
+
+    public void setOffice(Office office) {
+        this.office = office;
+    }
+
+    public String getOfficeName() {
+        return officeName;
+    }
+
+    public void setOfficeName(String officeName) {
+        this.officeName = officeName;
+    }
+
+    public String getHome() {
+        return home;
+    }
+
+    public void setHome(String home) {
+        this.home = home;
+    }
+
+    public String getForumDiscussionCreateByName() {
+        return forumDiscussionCreateByName;
+    }
+
+    public void setForumDiscussionCreateByName(String forumDiscussionCreateByName) {
+        this.forumDiscussionCreateByName = forumDiscussionCreateByName;
+    }
+
+    public Date getForumDiscussionCreateDate() {
+        return forumDiscussionCreateDate;
+    }
+
+    public void setForumDiscussionCreateDate(Date forumDiscussionCreateDate) {
+        this.forumDiscussionCreateDate = forumDiscussionCreateDate;
+    }
+}

+ 89 - 0
src/main/java/com/jeeplus/modules/forum/entity/ForumRecord.java

@@ -0,0 +1,89 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.modules.forum.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+import com.jeeplus.modules.sys.entity.User;
+import org.hibernate.validator.constraints.Length;
+
+import java.util.Date;
+
+
+/**
+ * 通知通告记录Entity
+ * @author jeeplus
+ * @version 2014-05-16
+ */
+public class ForumRecord extends DataEntity<ForumRecord> {
+
+	private static final long serialVersionUID = 1L;
+	private Forum forum;		// 通知通告ID
+	private User user;		// 接受人
+	private String readFlag;		// 阅读标记(0:未读;1:已读)
+	private Date readDate;		// 阅读时间
+	private String officeId; //部门id
+	private String officeName; //部门id
+
+
+	public ForumRecord() {
+		super();
+	}
+
+	public ForumRecord(String id){
+		super(id);
+	}
+
+	public ForumRecord(Forum forum){
+		this.forum = forum;
+	}
+
+	public Forum getForum() {
+		return forum;
+	}
+
+	public void setForum(Forum forum) {
+		this.forum = forum;
+	}
+
+	public User getUser() {
+		return user;
+	}
+
+	public void setUser(User user) {
+		this.user = user;
+	}
+	
+	@Length(min=0, max=1, message="阅读标记(0:未读;1:已读)长度必须介于 0 和 1 之间")
+	public String getReadFlag() {
+		return readFlag;
+	}
+
+	public void setReadFlag(String readFlag) {
+		this.readFlag = readFlag;
+	}
+	
+	public Date getReadDate() {
+		return readDate;
+	}
+
+	public void setReadDate(Date readDate) {
+		this.readDate = readDate;
+	}
+
+	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;
+	}
+}

+ 60 - 0
src/main/java/com/jeeplus/modules/forum/entity/ForumView.java

@@ -0,0 +1,60 @@
+package com.jeeplus.modules.forum.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+
+import java.util.Date;
+
+/**
+ * @author: 大猫
+ * @create: 2020-12-03 16:54
+ **/
+public class ForumView extends DataEntity<ForumView> {
+
+    private static final long serialVersionUID = 1L;
+
+    private String afficheId;  //公告id
+    private String userId;  //访问用户id
+    private Date firstVisitTime;  //首次访问时间
+    private Date lastVisitTime;   //最有一次访问时间
+    private Integer visitCount;  //访问次数
+
+    public String getAfficheId() {
+        return afficheId;
+    }
+
+    public void setAfficheId(String afficheId) {
+        this.afficheId = afficheId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public Date getFirstVisitTime() {
+        return firstVisitTime;
+    }
+
+    public void setFirstVisitTime(Date firstVisitTime) {
+        this.firstVisitTime = firstVisitTime;
+    }
+
+    public Date getLastVisitTime() {
+        return lastVisitTime;
+    }
+
+    public void setLastVisitTime(Date lastVisitTime) {
+        this.lastVisitTime = lastVisitTime;
+    }
+
+    public Integer getVisitCount() {
+        return visitCount;
+    }
+
+    public void setVisitCount(Integer visitCount) {
+        this.visitCount = visitCount;
+    }
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 1418 - 0
src/main/java/com/jeeplus/modules/forum/service/ForumService.java


Diferenças do arquivo suprimidas por serem muito extensas
+ 1161 - 0
src/main/java/com/jeeplus/modules/forum/web/ForumController.java


+ 1 - 1
src/main/java/com/jeeplus/modules/ruralprojectrecords/dao/RuralProjectRecordsDao.java

@@ -239,7 +239,7 @@ public interface RuralProjectRecordsDao extends CrudDao<RuralProjectRecords> {
      * @param projectName
      * @return
      */
-    Integer getProjectByName(String projectName);
+    Integer getProjectByName(RuralProjectRecords projectRecords);
 
     /**
      * 根据项目id查询项目创建人和责任人

+ 3 - 3
src/main/java/com/jeeplus/modules/ruralprojectrecords/service/RuralProjectRecordsService.java

@@ -4321,9 +4321,9 @@ public class RuralProjectRecordsService extends CrudService<RuralProjectRecordsD
 	/**
 	 * 项目登记进行判断项目名称是否重复
 	 */
-	public Integer reProjectName(String projectName){
-		 Integer projectRecords = dao.getProjectByName(projectName);
-		 return projectRecords;
+	public Integer reProjectName(RuralProjectRecords projectRecords){
+		 Integer projectRecordCount = dao.getProjectByName(projectRecords);
+		 return projectRecordCount;
 	}
 	@Transactional(readOnly = false)
 	public void projectUpgrade(RuralProjectRecords ruralProjectRecords){

+ 1 - 1
src/main/java/com/jeeplus/modules/ruralprojectrecords/web/RuralProjectRecordsController.java

@@ -1504,7 +1504,7 @@ public class RuralProjectRecordsController extends BaseController {
 	@ResponseBody
 	public Integer reProjectName(RuralProjectRecords projectRecords, RedirectAttributes redirectAttributes) {
 		if(StringUtils.isNotBlank(projectRecords.getProjectName())){
-			Integer projectNameCount = projectRecordsService.reProjectName(projectRecords.getProjectName());
+			Integer projectNameCount = projectRecordsService.reProjectName(projectRecords);
 			return projectNameCount;
 		}
 		return 0;

+ 11 - 13
src/main/java/com/jeeplus/modules/workinvoice/web/WorkInvoiceAllController.java

@@ -14,6 +14,7 @@ import com.jeeplus.common.persistence.Page;
 import com.jeeplus.common.utils.DateUtils;
 import com.jeeplus.common.utils.MyBeanUtils;
 import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.common.utils.ThisLocalityDownloadUtil;
 import com.jeeplus.common.utils.excel.ExportExcel;
 import com.jeeplus.common.utils.excel.ExportMultipleTabsExcel;
 import com.jeeplus.common.utils.excel.ImportExcel;
@@ -21,14 +22,14 @@ import com.jeeplus.common.web.BaseController;
 import com.jeeplus.modules.act.entity.Act;
 import com.jeeplus.modules.act.service.ActTaskService;
 import com.jeeplus.modules.act.utils.ActUtils;
-import com.jeeplus.modules.projectmaterialstorage.entity.ProjectMaterialStorage;
-import com.jeeplus.modules.projectmaterialstorage.entity.ProjectMaterialStorageImport;
-import com.jeeplus.modules.projectrecord.entity.AdminProjectReportedImport;
 import com.jeeplus.modules.projectrecord.entity.ProjectRecords;
 import com.jeeplus.modules.projectrecord.enums.ProjectStatusEnum;
 import com.jeeplus.modules.projectrecord.service.ProjectRecordsService;
 import com.jeeplus.modules.ruralprojectrecords.service.RuralProjectRecordsService;
-import com.jeeplus.modules.sys.entity.*;
+import com.jeeplus.modules.sys.entity.MainDictDetail;
+import com.jeeplus.modules.sys.entity.Office;
+import com.jeeplus.modules.sys.entity.Role;
+import com.jeeplus.modules.sys.entity.User;
 import com.jeeplus.modules.sys.service.AreaService;
 import com.jeeplus.modules.sys.service.OfficeService;
 import com.jeeplus.modules.sys.utils.DictUtils;
@@ -1646,18 +1647,15 @@ public class WorkInvoiceAllController extends BaseController {
 	 * @param redirectAttributes
 	 * @return
 	 */
-	@RequiresPermissions("project:adminProjectReportedImport:import")
-	@RequestMapping(value = "import/invoiceBatchTemplate")
-	public String invoiceBatchTemplate(HttpServletResponse response, RedirectAttributes redirectAttributes) {
+	//@RequiresPermissions("project:adminProjectReportedImport:import")
+	@RequestMapping(value = "importReceiptDataFile/invoiceBatchTemplate")
+	public void invoiceBatchTemplate(HttpServletResponse response, RedirectAttributes redirectAttributes) {
 		try {
-			String fileName = "管理员上报导入模板.xlsx";
-			List<AdminProjectReportedImport> list = Lists.newArrayList();
-			new ExportExcel("项目上报数据", AdminProjectReportedImport.class, 1).setDataList(list).write(response, fileName).dispose();
-			return null;
+			ThisLocalityDownloadUtil download = new ThisLocalityDownloadUtil();
+			download.download("收款导入模版.xlsx",request,response);
 		} catch (Exception e) {
-			addMessage(redirectAttributes, "导入模板下载失败!失败信息:"+e.getMessage());
+			logger.error("收款导入模版下载失败!",e);
 		}
-		return "redirect:"+ Global.getAdminPath()+"/project/adminProjectReportedImport/?repage";
 	}
 
 

+ 43 - 0
src/main/java/com/jeeplus/modules/workprojectnotify/web/WorkProjectNotifyController.java

@@ -36,6 +36,8 @@ import com.jeeplus.modules.externalUnit.service.ExternalUnitCapitalDemandService
 import com.jeeplus.modules.externalUnit.service.ExternalUnitFeedbackService;
 import com.jeeplus.modules.filialeWorkInvoice.entity.FilialeWorkInvoice;
 import com.jeeplus.modules.filialeWorkInvoice.service.FilialeWorkInvoiceService;
+import com.jeeplus.modules.forum.entity.ForumDiscussionUser;
+import com.jeeplus.modules.forum.service.ForumService;
 import com.jeeplus.modules.iim.entity.MailBox;
 import com.jeeplus.modules.iim.entity.MailPage;
 import com.jeeplus.modules.iim.service.MailBoxService;
@@ -623,6 +625,9 @@ public class WorkProjectNotifyController extends BaseController {
 	@Autowired
 	private MilitaryIndustryConfidentialityService militaryIndustryConfidentialityService;
 
+	@Autowired
+	private ForumService forumService;
+
 
 	@ModelAttribute
 	public WorkProjectNotify get(@RequestParam(required = false) String id) {
@@ -2556,6 +2561,10 @@ public class WorkProjectNotifyController extends BaseController {
 					} else if (workProjectNotify.getRemarks().contains("重新申请") && !"1".equals(workProjectNotify.getStatus())) {
 						return "modules/workinvoice/conditionWorkInvoiceModify";
 					}
+				}else if (workProjectNotify.getType().equals("415")) {    //论坛加入申请
+
+					return this.forumAudit(workProjectNotify, model);
+
 				}/* else if (workProjectNotify.getType().equals("24")) {
 					Leave oaLeave = leaveService.get(workProjectNotify.getNotifyId());
 					oaLeave.setAct(getByAct(oaLeave.getProcessInstanceId()));
@@ -11485,4 +11494,38 @@ public class WorkProjectNotifyController extends BaseController {
 		return "modules/militaryIndustryConfidentiality/militaryIndustryConfidentialityView";
     }
 
+	/**
+	 * 论坛加入申请
+	 * @param workProjectNotify
+	 * @param model
+	 * @return
+	 */
+	private String forumAudit(WorkProjectNotify workProjectNotify,Model model) {
+		ForumDiscussionUser forumDiscussionUser = forumService.getForumDiscussionUserById(workProjectNotify.getNotifyId());
+
+		forumDiscussionUser.setAct(getByAct(forumDiscussionUser.getProcessInstanceId()));
+		if(StringUtils.isNotBlank(workProjectNotify.getHome())){
+			forumDiscussionUser.setHome(workProjectNotify.getHome());
+		}else{
+			forumDiscussionUser.setHome("home");
+		}
+
+		Act act = getByAct(forumDiscussionUser.getProcessInstanceId());
+		forumDiscussionUser.setAct(act);
+
+		model.addAttribute("forumDiscussionUser", forumDiscussionUser);
+
+
+		if (workProjectNotify.getRemarks().contains("待通知") || "view".equals(workProjectNotify.getView())) {
+			return "modules/forum/forumDiscussionView";
+		}else if (workProjectNotify.getRemarks().contains("待审批") && !"1".equals(workProjectNotify.getStatus())) {
+			model.addAttribute("identification","forum");
+			model.addAttribute("identificationName","论坛申请审核意见");
+			model.addAttribute("projectNotifyType", "论坛申请");
+			return "modules/forum/forumAudit";
+		} else {
+			return "modules/forum/forumDiscussionView";
+		}
+	}
+
 }

Diferenças do arquivo suprimidas por serem muito extensas
+ 1150 - 0
src/main/resources/mappings/modules/forum/ForumDao.xml


+ 69 - 0
src/main/resources/mappings/modules/forum/ForumDiscussionDao.xml

@@ -0,0 +1,69 @@
+<?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.forum.dao.ForumDiscussionDao">
+
+	<insert id="saveForumDiscussion">
+		INSERT INTO forum_discussion (
+			id,
+			create_by,
+			create_date,
+			update_by,
+			update_date,
+			remarks,
+			del_flag,
+			name
+		) VALUES (
+					 #{id},
+					 #{createBy.id},
+					 #{createDate},
+					 #{updateBy.id},
+					 #{updateDate},
+					 #{remarks},
+					 #{delFlag},
+					 #{name}
+				 )
+	</insert>
+
+	<update id="updateForumDiscussion">
+		update
+			forum_discussion
+		set
+			update_by = #{updateBy.id},
+			update_date = #{updateDate},
+			name = #{name}
+		where id = #{id}
+	</update>
+
+	<update id="deleteForumDiscussion">
+		update
+			forum_discussion
+		set
+			update_by = #{updateBy.id},
+			update_date = #{updateDate},
+			del_flag = 1
+		where id = #{id}
+	</update>
+
+
+	<select id="getMyForumDiscussionList" resultType="ForumDiscussion">
+		select
+		a.id AS "id",
+		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",
+		a.remarks AS "remarks",
+		a.name as "name"
+		from
+		forum_discussion a
+		<where>
+			a.del_flag = 0
+			<if test="name != null and name != ''">
+				AND a.name = #{name}
+			</if>
+			and a.create_by = #{createBy.id}
+		</where>
+	</select>
+
+</mapper>

+ 177 - 0
src/main/resources/mappings/modules/forum/ForumRecordDao.xml

@@ -0,0 +1,177 @@
+<?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.forum.dao.ForumRecordDao">
+
+	<sql id="forumRecordColumns">
+		a.ID AS "id",
+		a.forum_id AS "forum.id",
+		a.USER_ID AS "user.id",
+		a.READ_FLAG AS "readFlag",
+		a.READ_DATE AS "readDate",
+		u.name AS "user.name",
+		o.name AS "user.office.name",
+		o.name AS "user.officeName",
+		so.name AS "officeName"
+	</sql>
+		<sql id="forumRecordColumn">
+		a.ID AS "id",
+		a.forum_id AS "forum.id",
+		a.USER_ID AS "user.id",
+		a.READ_FLAG AS "readFlag",
+		a.READ_DATE AS "readDate"
+
+	</sql>
+
+
+
+	<sql id="forumRecordJoins">
+		LEFT JOIN sys_user u ON u.id = a.user_id
+		LEFT JOIN sys_office o ON o.id = u.office_id
+		LEFT JOIN sys_office so ON so.id = a.office_id
+	</sql>
+
+	<select id="get" resultType="ForumRecord">
+		SELECT
+			<include refid="forumRecordColumns"/>
+		FROM forum_record a
+		<include refid="forumRecordJoins"/>
+		WHERE a.id = #{id}
+	</select>
+
+	<select id="findList" resultType="ForumRecord">
+		SELECT
+			<include refid="forumRecordColumns"/>
+		FROM forum_record a
+		<include refid="forumRecordJoins"/>
+		WHERE 1=1
+		<if test="forum != null and forum.id != null and forum.id != ''">
+			AND oa_notify_id = #{forum.id}
+		</if>
+		AND a.read_flag=#{readFlag}
+		AND a.office_id is NULL
+		ORDER BY a.read_flag ASC
+	</select>
+
+	<select id="findOffices" resultType="ForumRecord">
+		SELECT
+		<include refid="forumRecordColumns"/>
+		FROM forum_record a
+		<include refid="forumRecordJoins"/>
+		WHERE a.user_id is NULL
+		<if test="forum != null and forum.id != null and forum.id != ''">
+			AND oa_notify_id = #{forum.id}
+		</if>
+		ORDER BY a.id ASC
+	</select>
+	<select id="findUsers" resultType="ForumRecord">
+		SELECT
+		<include refid="forumRecordColumns"/>
+		FROM forum_record a
+		<include refid="forumRecordJoins"/>
+		WHERE a.office_id is NULL
+		<if test="forum != null and forum.id != null and forum.id != ''">
+			AND oa_notify_id = #{forum.id}
+		</if>
+		ORDER BY a.id ASC
+	</select>
+
+	<!--PC端使用:包含已读和未读 -->
+	<select id="findList2" resultType="ForumRecord">
+		SELECT
+		<include refid="forumRecordColumns"/>
+		FROM forum_record a
+		<include refid="forumRecordJoins"/>
+		WHERE 1=1
+		<if test="forumRecord != null and forumRecord.id != null and forumRecord.id != ''">
+			AND a.oa_notify_id = #{forumRecord.id}
+		</if>
+		AND a.office_id is NULL
+		ORDER BY a.read_flag ASC
+	</select>
+
+		<select id="findUserList" resultType="ForumRecord">
+		SELECT
+			<include refid="forumRecordColumn"/>
+		FROM forum_record a
+		WHERE a.read_flag=#{readFlag}
+			AND a.oa_notify_id = #{forum.id}
+	</select>
+
+	<select id="findAllList" resultType="ForumRecord">
+		SELECT
+			<include refid="forumRecordColumns"/>
+		FROM forum_record a
+		<include refid="forumRecordJoins"/>
+		WHERE 1=1
+		ORDER BY a.read_flag ASC
+	</select>
+
+	<insert id="insert">
+		INSERT INTO forum_record(
+			ID,
+			forum_id,
+			USER_ID,
+			READ_FLAG,
+			READ_DATE
+		) VALUES (
+			#{id},
+			#{forum.id},
+			#{user.id},
+			#{readFlag},
+			#{readDate}
+		)
+	</insert>
+
+	<insert id="insertAll" parameterType="List">
+		INSERT INTO forum_record(
+			ID,
+		forum_id,
+			USER_ID,
+			READ_FLAG,
+			READ_DATE
+		)
+		<foreach collection="list" item="e" separator=" UNION ALL ">
+			SELECT
+				#{e.id},
+				#{e.forum.id},
+				#{e.user.id},
+				#{e.readFlag},
+				#{e.readDate}
+			FROM dual
+		</foreach>
+	</insert>
+	<insert id="insertOfficeAll" parameterType="List">
+		INSERT INTO forum_record(
+			ID,
+		forum_id,
+			OFFICE_ID
+		)
+		<foreach collection="list" item="e" separator=" UNION ALL ">
+			SELECT
+				#{e.id},
+				#{e.forum.id},
+				#{e.officeId}
+			FROM dual
+		</foreach>
+	</insert>
+
+	<update id="update">
+		UPDATE forum_record SET
+			READ_FLAG = #{readFlag},
+			READ_DATE = #{readDate}
+		WHERE forum_id = #{forum.id}
+			AND USER_ID = #{user.id}
+			AND READ_FLAG != '1'
+	</update>
+
+	<delete id="delete">
+		DELETE FROM forum_record
+		WHERE id = #{id}
+	</delete>
+
+	<update id="deleteByForumId">
+		UPDATE forum_record SET READ_FLAG = ''
+		WHERE oa_notify_id = #{forumId}
+	</update>
+
+</mapper>

+ 1 - 1
src/main/resources/mappings/modules/ruralprojectrecords/RuralProjectRecordsDao.xml

@@ -3100,7 +3100,7 @@
 		select
 		count(a.id)
 		FROM rural_project_records a
-		where a.project_name=#{projectName}  and a.`status`!=7 and a.del_flag = 0
+		where a.project_name=#{projectName} and a.id != #{id}  and a.`status`!=7 and a.del_flag = 0
 	</select>
 
     <update id="updateReportDataTwo">

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

@@ -5,7 +5,7 @@
 
 <!-- 导入按钮,原样保留 -->
 <button id="btnImport" class="layui-btn layui-btn-sm layui-bg-blue" data-toggle="tooltip" data-placement="left" title="导入">
-    导入
+    批量收款导入
 </button>
 
 <!-- 弹窗内容,仅保留文件选择,删除form的action、method,彻底禁用传统表单提交 -->

+ 163 - 0
src/main/webapp/webpage/modules/forum/forumAudit.jsp

@@ -0,0 +1,163 @@
+<%@ 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 src="${ctxStatic}/common/html/js/script.js"></script>
+    <script type="text/javascript">
+        var validateForm;
+
+        function doSubmit(obj) {//回调函数,在编辑和保存动作时,供openDialog调用提交表单。
+            if (validateForm.form()) {
+                if (obj == 1) {
+                    $('#flag').val('yes');
+                } else {
+                    $('#flag').val('no');
+                }
+                $("#inputForm").submit();
+                return true;
+            } else {
+                parent.layer.msg("信息未填写完整!", {icon: 5});
+            }
+
+            return false;
+        }
+
+        function arraysEqual() {
+            const idArray = allDataList.map(item => item.id);
+            if (confirmIdList.length !== idArray.length) return false;
+            const sortedA1 = [...confirmIdList].sort();
+            const sortedA2 = [...idArray].sort();
+            return sortedA1.every((val, idx) => val === sortedA2[idx]);
+        }
+
+        $(document).ready(function () {
+            layui.use('form', 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>
+    <style>
+        /*超过5个汉字,调整label的长度,以下是配套的*/
+        .layui-item .layui-form-label {
+            width: 90px;
+        }
+
+        .form-group .layui-item .layui-input-block,
+        .query .layui-input-block {
+            margin-left: 116px;
+        }
+
+        #reimbursementElectronicInvoiceVATTaxes td {
+            padding-left: 0px;
+            padding-right: 0px;
+        }
+    </style>
+</head>
+<body>
+<div class="single-form">
+    <div class="container view-form">
+        <form:form id="inputForm" modelAttribute="forumDiscussionUser" enctype="multipart/form-data"
+                   action="${ctx}/forum/forum/saveAudit" method="post"
+                   class="form-horizontal layui-form">
+            <form:hidden path="id"/>
+            <form:hidden path="home"/>
+            <form:hidden path="processInstanceId"/>
+            <form:hidden path="act.taskId"/>
+            <form:hidden path="act.taskName"/>
+            <form:hidden path="act.taskDefKey"/>
+            <form:hidden path="act.procInsId"/>
+            <form:hidden path="act.procDefId"/>
+            <form:hidden id="flag" path="act.flag"/>
+            <input type="hidden" id="opinion" name="act.comment" value="" maxlength="255">
+            <div class="form-group layui-row first ">
+                <div class="form-group-label"><h2>基础信息</h2></div>
+
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label double-line">申请的论坛名称:</label>
+                    <div class="layui-input-block">
+                        <form:input path="forumDiscussionName" cssStyle="background-color: #f1f1f1" htmlEscape="false"
+                                    readonly="true" id="forumDiscussionName" class="form-control layui-input"
+                                    value="${forumDiscussionUser.forumDiscussionName}"/>
+                    </div>
+                </div>
+
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label">申请人:</label>
+                    <div class="layui-input-block">
+                        <form:input path="userName" cssStyle="background-color: #f1f1f1" htmlEscape="false"
+                                    readonly="true" id="userName" class="form-control layui-input"
+                                    value="${forumDiscussionUser.userName}"/>
+                    </div>
+                </div>
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label">所属部门:</label>
+                    <div class="layui-input-block">
+                        <input htmlEscape="false" style="background-color: #f1f1f1" readonly="true"
+                               class="form-control layui-input" value="${forumDiscussionUser.officeName}"/>
+                    </div>
+                </div>
+
+
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label">申请时间:</label>
+                    <div class="layui-input-block">
+                        <input readonly="readonly" style="background-color: #f1f1f1" class="form-control layui-input"
+                               value="<fmt:formatDate value="${forumDiscussionUser.createDate}" pattern="yyyy-MM-dd"/>"/>
+                    </div>
+                </div>
+
+
+            </div>
+
+
+
+            <div class="form-group layui-row page-end"></div>
+        </form:form>
+        <div class="form-group-label">
+            <div style="float: right"><a href="javascript:void(0)" style='background-color: #FFB800'
+                                         onclick="openDialogre('个人模板列表', '${ctx}/auditTemplate/auditTemplate/templateList?identification=${identification}&name=${identificationName}','80%', '70%','','关闭')"
+                                         class="nav-btn layui-btn layui-btn-sm"><i class="fa fa-file-excel-o"></i>
+                审核意见模板列表</a></div>
+            <h2>审批意见</h2>
+        </div>
+        <iframe id="iframe" src="${ctx}/auditTemplate/auditTemplate/iframeView?identification=${identification}"
+                name="listresult" frameborder="0" align="left" width="100%" height="300" scrolling="value"></iframe>
+        <div class="form-group layui-row">
+            <div class="form-group-label"><h2>${projectNotifyType}审批流程</h2></div>
+            <div class="layui-item layui-col-xs12 form-table-container">
+                <act:flowChart procInsId="${forumDiscussionUser.act.procInsId}"/>
+                <act:histoicFlow procInsId="${forumDiscussionUser.act.procInsId}"/>
+            </div>
+        </div>
+    </div>
+</div>
+</body>
+</html>
+

+ 428 - 0
src/main/webapp/webpage/modules/forum/forumAuditRecordList.jsp

@@ -0,0 +1,428 @@
+<%@ 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">
+
+		$(function () {
+			$(".btn btn-white btn-sm").bind("click",function () {
+
+            })
+        });
+
+        $(document).ready(function() {
+            //搜索框收放
+            $('#moresee').click(function(){
+                if($('#moresees').is(':visible'))
+                {
+                    $('#moresees').slideUp(0,resizeListWindow1);
+                    $('#moresee i').removeClass("glyphicon glyphicon-menu-up").addClass("glyphicon glyphicon-menu-down");
+                }else{
+                    $('#moresees').slideDown(0,resizeListWindow1);
+                    $('#moresee i').removeClass("glyphicon glyphicon-menu-down").addClass("glyphicon glyphicon-menu-up");
+                }
+            });
+            laydate.render({
+                elem: '#createStartDate', //目标元素。由于laydate.js封装了一个轻量级的选择器引擎,因此elem还允许你传入class、tag但必须按照这种方式 '#id .class'
+                event: 'focus', //响应事件。如果没有传入event,则按照默认的click
+                type : 'date'
+            });
+            laydate.render({
+                elem: '#createEndDate', //目标元素。由于laydate.js封装了一个轻量级的选择器引擎,因此elem还允许你传入class、tag但必须按照这种方式 '#id .class'
+                event: 'focus', //响应事件。如果没有传入event,则按照默认的click
+                type : 'date'
+            });
+        });
+
+        function openDialog(title,url,width,height,target) {
+			var type = '${type}'
+			// 👇 这里加判断:type 为空就提示,并且直接返回,不打开弹窗
+			if(!type || type == null || type == ''){
+				top.layer.msg('请先选择左侧需要添加帖子的论坛', {icon: 7, time: 2000});
+				return;
+			}
+
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {//如果是移动端,就使用自适应大小弹窗
+                width = 'auto';
+                height = 'auto';
+            } else {//如果是PC端,根据用户设置的width和height显示。
+
+            }
+
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: title,
+                maxmin: true, //开启最大化最小化按钮
+                content: url,
+                skin: 'two-btns',
+                btn: ['提交', '关闭'],
+                yes: 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
+                    }
+                },
+				cancel: function (index) {
+                }
+            });
+        }
+
+        function openDialogView(title,url,width,height,target) {
+
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {//如果是移动端,就使用自适应大小弹窗
+                width = 'auto';
+                height = 'auto';
+            } else {//如果是PC端,根据用户设置的width和height显示。
+
+            }
+
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: title,
+                maxmin: true, //开启最大化最小化按钮
+                content: url,
+                skin: 'two-btns',
+                btn: [ '关闭'],
+
+				cancel: function (index) {
+                }
+            });
+        }
+
+        function openDialogAdmin(title,url,width,height,target) {
+
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {//如果是移动端,就使用自适应大小弹窗
+                width = 'auto';
+                height = 'auto';
+            } else {//如果是PC端,根据用户设置的width和height显示。
+
+            }
+
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: title,
+                maxmin: true, //开启最大化最小化按钮
+                content: url,
+                skin: 'three-btns',
+                btn: ['提交', '关闭'],
+                btn1: function(index, layero){
+                    var body = top.layer.getChildFrame('body', index);
+                    var iframeWin = layero.find('iframe')[0]; //得到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 openDialogre(title,url,width,height,target,buttons) {
+
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {//如果是移动端,就使用自适应大小弹窗
+                width = 'auto';
+                height = 'auto';
+            } else {//如果是PC端,根据用户设置的width和height显示。
+
+            }
+            var split = buttons.split(",");
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: title,
+                maxmin: true, //开启最大化最小化按钮
+                skin: 'three-btns',
+                content: url,
+                btn: split,
+                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,layero){
+                    if(split.length==2){return}
+                    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(2) ){
+                        // top.layer.close(index);//关闭对话框。
+                        setTimeout(function(){top.layer.close(index)}, 100);//延时0.1秒,对应360 7.1版本bug
+                    }else {
+                        return false;
+                    }
+                },
+                btn3: function (index) {
+                }
+            });
+        }
+
+
+		//打开对话框(查看)
+		function openDialogListView(title,url,id,width,height){
+
+
+			if(navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)){//如果是移动端,就使用自适应大小弹窗
+				width='auto';
+				height='auto';
+			}else{//如果是PC端,根据用户设置的width和height显示。
+
+			}
+			$.ajax({
+				async: false,
+				url: "${ctx}/forum/forum/getForum?id="+id,
+				dataType: "json",
+				success: function (data) {
+					if(data.success){
+						top.layer.open({
+							type: 2,
+							skin: 'one-btn',
+							area: [width, height],
+							title: title,
+							maxmin: true, //开启最大化最小化按钮
+							content: url ,
+							btn: ['关闭'],
+							cancel: function(index){
+							}
+						});
+					}else{
+						top.layer.msg("该帖子信息已删除!", {icon: 0});
+						window.location.reload();
+					}
+				}
+			});
+
+		}
+
+
+		function sortOrRefresh(){//刷新或者排序,页码不清零
+
+			$("#searchForm").submit();
+			return false;
+		}
+	</script>
+
+	<style>
+		body{
+			background-color:transparent;
+			filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#26FFFFFF, endColorstr=#26FFFFFF);
+			color:#ffffff;
+			background-color:rgba(255,255,255,0);
+			height:100%;
+		}
+	</style>
+</head>
+<body>
+<div class="wrapper wrapper-content">
+	<sys:message content="${message}"/>
+	<div class="layui-row">
+		<div class="full-width fl">
+			<div class="contentShadow layui-row" id="queryDiv">
+
+			<form:form id="searchForm" modelAttribute="forum" action="${ctx}/forum/forum/myApplyList" 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="1"/>--%>
+			<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="title" htmlEscape="false" maxlength="200"  class=" form-control layui-input" />
+						</div>
+					</div>
+
+					<div class="layui-item query athird">
+						<label class="layui-form-label">帖子内容:</label>
+						<div class="layui-input-block with-icon">
+							<form:input path="content" htmlEscape="false" maxlength="200"  class=" form-control layui-input"/>
+						</div>
+					</div>
+
+					<div class="layui-item athird">
+						<div class="input-group">
+							<a href="#" id="moresee"><i class="glyphicon glyphicon-menu-down"></i></a>
+							<div class="layui-btn-group search-spacing">
+								<button id="searchQuery" class="layui-btn layui-btn-sm  layui-bg-blue" onclick="search()">查询</button>
+								<button id="searchReset" class="layui-btn layui-btn-sm  " onclick="resetSearch()">重置</button>
+							</div>
+						</div>
+					</div>
+					<div style="    clear:both;"></div>
+				</div>--%>
+				<%--<div id="moresees" style="clear:both;display:none;">
+
+					<div class="layui-item query athird">
+						<label class="layui-form-label">创建日期:</label>
+						<div class="layui-input-block readOnlyFFF">
+							<input id="createStartDate" name="createStartDate" type="text" readonly="readonly" maxlength="20" class="laydate-icondate form-control layer-date layui-input laydate-icon query-group"
+								   value="<fmt:formatDate value="${forum.createStartDate}" pattern="yyyy-MM-dd"/>"/>
+							</input>
+							<span class="group-sep">-</span>
+							<input id="createEndDate" name="createEndDate" type="text" readonly="readonly" maxlength="20" class="laydate-icondate form-control layer-date layui-input laydate-icon query-group"
+								   value="<fmt:formatDate value="${forum.createEndDate}" pattern="yyyy-MM-dd"/>"/>
+							</input>
+						</div>
+					</div>
+
+					<div class="layui-item query athird">
+						<label class="layui-form-label">创建人:</label>
+						<div class="layui-input-block with-icon">
+							<form:input path="createBy.name" htmlEscape="false" maxlength="200"  class=" form-control layui-input"/>
+						</div>
+					</div>
+
+
+					<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">
+						<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 }
+            ,elem: '#contentTable'
+            ,page: false
+            ,cols: [[
+                // {checkbox: true, fixed: true},
+                {field:'index',align:'center',  width:40,title: '序号'}
+                ,{field:'forumDiscussionName',align:'center', title: '论坛名称', minWidth:200,templet:function(d){
+                    return "<span title='"+ d.forumDiscussionName +"'>" + d.forumDiscussionName + "</span>";
+                }}
+                ,{field:'forumDiscussionCreateByName', align:'center',title: '论坛创建人', width:80,templet:function(d){
+                        return "<span title='"+ d.forumDiscussionCreateByName +"'>" + d.forumDiscussionCreateByName + "</span>";
+                    }}
+                ,{field:'forumDiscussionCreateDate', align:'center',title: '论坛创建时间',width:150,templet:function(d){
+						return "<span title='"+ d.forumDiscussionCreateDate +"'>" + d.forumDiscussionCreateDate + "</span>";
+					}}
+                ,{field:'createByName', align:'center',title: '申请人',width:150,templet:function(d){
+						return "<span title='"+ d.createByName +"'>" + d.createByName + "</span>";
+					}}
+                ,{field:'createDate', align:'center',title: '申请加入时间',width:150,templet:function(d){
+						return "<span title='"+ d.createDate +"'>" + d.createDate + "</span>";
+					}}
+
+				,{align:'center', title: '状态',  width:70,templet:function(d){
+						var st = getAuditState(d.status);
+						if(st.action)
+							var xml ="<span onclick=\"openDialogView('流程追踪', '${ctx}/forum/forum/getProcess?id=" + d.id + "&processInstanceId=" + d.processInstanceId + "','95%','95%')\" class=\"status-label status-label-" + st.label + "\" >" + st.status + "</span>";
+						else
+							var xml = "<span style=\"cursor:default;\" class=\"status-label status-label-" + st.label + "\" >" + st.status + "</span>";
+						return xml;
+					}}
+
+                ,{align:'center',title:"操作",width:130,templet:function(d){
+                        ////对操作进行初始化
+                        var xml = "<div class=\"layui-btn-group\">";
+
+						if(d.cancancel != undefined && d.cancancel =="1")
+						{
+							xml+="<a href=\"${ctx}/forum/forum/revoke?id=" + d.id + "&processInstanceId=" + d.procId + "&status="+d.status+"\" onclick=\"return confirmx('确认要撤回该申请吗?', this.href)\" class=\"layui-btn layui-btn-xs layui-bg-red\" > 撤回</a>";
+						}
+						xml+="</div>"
+                            return xml;
+                    }}
+            ]]
+            ,data: [
+                <c:if test="${ not empty page.list}">
+                <c:forEach items="${page.list}" var="forum" varStatus="index">
+                <c:if test="${index.index != 0}">,</c:if>
+                {
+                    "index":"${index.index+1}"
+                    ,"id":"${forum.id}"
+                    ,"forumDiscussionName":"${forum.forumDiscussionName}"
+                    ,"forumDiscussionCreateByName":"${forum.forumDiscussionCreateByName}"
+					,"forumDiscussionCreateDate":"<fmt:formatDate value="${forum.forumDiscussionCreateDate}" pattern="yyyy-MM-dd HH:mm:ss"/>"
+                    ,"createByName":"${forum.createBy.name}"
+					,"createDate":"<fmt:formatDate value="${forum.createDate}" pattern="yyyy-MM-dd HH:mm:ss"/>"
+                    ,"processInstanceId":"${forum.processInstanceId}"
+					,"status":"${forum.status}"
+
+
+					,"cancancel": <c:choose><c:when test="${fns:getUser().id == forum.createBy.id}">"1"</c:when><c:otherwise>"0"</c:otherwise></c:choose>
+                }
+                </c:forEach>
+                </c:if>
+            ]
+            // ,even: true
+            // ,height: 315
+        });
+
+    })
+
+    resizeListTable();
+</script>
+<script>
+    resizeListWindow1();
+    $(window).resize(function(){
+        resizeListWindow1();
+    });
+</script>
+</body>
+</html>

+ 153 - 0
src/main/webapp/webpage/modules/forum/forumDiscussionView.jsp

@@ -0,0 +1,153 @@
+<%@ 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 src="${ctxStatic}/common/html/js/script.js"></script>
+    <script type="text/javascript">
+        var validateForm;
+
+        function doSubmit(obj) {//回调函数,在编辑和保存动作时,供openDialog调用提交表单。
+            if (validateForm.form()) {
+                if (obj == 1) {
+                    $('#flag').val('yes');
+                } else {
+                    $('#flag').val('no');
+                }
+                $("#inputForm").submit();
+                return true;
+            } else {
+                parent.layer.msg("信息未填写完整!", {icon: 5});
+            }
+
+            return false;
+        }
+
+        function arraysEqual() {
+            const idArray = allDataList.map(item => item.id);
+            if (confirmIdList.length !== idArray.length) return false;
+            const sortedA1 = [...confirmIdList].sort();
+            const sortedA2 = [...idArray].sort();
+            return sortedA1.every((val, idx) => val === sortedA2[idx]);
+        }
+
+        $(document).ready(function () {
+            layui.use('form', 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>
+    <style>
+        /*超过5个汉字,调整label的长度,以下是配套的*/
+        .layui-item .layui-form-label {
+            width: 90px;
+        }
+
+        .form-group .layui-item .layui-input-block,
+        .query .layui-input-block {
+            margin-left: 116px;
+        }
+
+        #reimbursementElectronicInvoiceVATTaxes td {
+            padding-left: 0px;
+            padding-right: 0px;
+        }
+    </style>
+</head>
+<body>
+<div class="single-form">
+    <div class="container view-form">
+        <form:form id="inputForm" modelAttribute="forumDiscussionUser" enctype="multipart/form-data"
+                   action="${ctx}/forum/forum/saveAudit" method="post"
+                   class="form-horizontal layui-form">
+            <form:hidden path="id"/>
+            <form:hidden path="home"/>
+            <form:hidden path="processInstanceId"/>
+            <form:hidden path="act.taskId"/>
+            <form:hidden path="act.taskName"/>
+            <form:hidden path="act.taskDefKey"/>
+            <form:hidden path="act.procInsId"/>
+            <form:hidden path="act.procDefId"/>
+            <form:hidden id="flag" path="act.flag"/>
+            <input type="hidden" id="opinion" name="act.comment" value="" maxlength="255">
+            <div class="form-group layui-row first ">
+                <div class="form-group-label"><h2>基础信息</h2></div>
+
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label double-line">申请的论坛名称:</label>
+                    <div class="layui-input-block">
+                        <form:input path="forumDiscussionName" cssStyle="background-color: #f1f1f1" htmlEscape="false"
+                                    readonly="true" id="forumDiscussionName" class="form-control layui-input"
+                                    value="${forumDiscussionUser.forumDiscussionName}"/>
+                    </div>
+                </div>
+
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label">申请人:</label>
+                    <div class="layui-input-block">
+                        <form:input path="userName" cssStyle="background-color: #f1f1f1" htmlEscape="false"
+                                    readonly="true" id="userName" class="form-control layui-input"
+                                    value="${forumDiscussionUser.userName}"/>
+                    </div>
+                </div>
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label">所属部门:</label>
+                    <div class="layui-input-block">
+                        <input htmlEscape="false" style="background-color: #f1f1f1" readonly="true"
+                               class="form-control layui-input" value="${forumDiscussionUser.officeName}"/>
+                    </div>
+                </div>
+
+
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label">申请时间:</label>
+                    <div class="layui-input-block">
+                        <input readonly="readonly" style="background-color: #f1f1f1" class="form-control layui-input"
+                               value="<fmt:formatDate value="${forumDiscussionUser.createDate}" pattern="yyyy-MM-dd"/>"/>
+                    </div>
+                </div>
+
+
+            </div>
+
+            <div class="form-group layui-row">
+                <div class="form-group-label"><h2>${projectNotifyType}审批流程</h2></div>
+                <div class="layui-item layui-col-xs12 form-table-container" >
+                    <act:flowChart procInsId="${forumDiscussionUser.processInstanceId}"/>
+                    <act:histoicFlow procInsId="${forumDiscussionUser.processInstanceId}" />
+                </div>
+            </div>
+
+            <div class="form-group layui-row page-end"></div>
+        </form:form>
+    </div>
+</div>
+</body>
+</html>
+

+ 157 - 0
src/main/webapp/webpage/modules/forum/forumForm.jsp

@@ -0,0 +1,157 @@
+<%@ 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 src="${ctxStatic}/common/html/js/script.js"></script>
+    <style type="text/css">
+        img {width: 50px; height: 50px;}
+    </style>
+    <script type="text/javascript" src="${ctxStatic}/ckeditor/ckeditor.js"></script>
+    <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" language="JavaScript" for="window" event="onload">
+        var validateForm;
+        function doSubmit(i){//回调函数,在编辑和保存动作时,供openDialog调用提交表单。
+
+            if(validateForm.form()){
+
+                var content = CKEDITOR.instances.contents.document.getBody().getText();
+                while (content.indexOf("img{max-width:100%!important;") != -1){
+                    content = content.replace("img{max-width:100%!important;}","");
+                }
+                $("#content").val(content);
+                console.log(content+","+(content == null)+(content == undefined)+(content == ""));
+                if(content == null || content == undefined || content == "" || content == "\n"){
+                    parent.layer.msg('帖子内容不能为空',{icon:5});
+                    return false;
+                }
+                var flag=judgment();
+                if (!flag){
+                    return flag;
+                }
+
+                $("#inputForm").submit();
+                return true;
+            }else {
+                parent.layer.msg("信息未填写完整!", {icon: 5});
+            }
+
+            return false;
+        }
+        $(document).ready(function() {
+            layui.use(['form', 'layer'], function () {
+                var form = layui.form;
+            });
+            //$("#name").focus();
+            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);
+                    }
+                }
+            });
+            //只做查看时,禁用掉以下标签
+            $('input,textarea,select').attr('disabled',<%=request.getAttribute("disabled")%>);
+        });
+    </script>
+    <script type="text/javascript">
+        function insertTitleCollection(tValue){
+            var list = "${forum.workAttachments}";
+            var size = (list.split('url')).length-1;
+            var files = tValue;
+            for(var i = 0;i<files.length;i++) {
+                var file = files[i];
+                var attachmentId = "";
+                var attachmentFlag = "0409";
+                console.log(file);
+                var timestamp = new Date().getTime();
+
+                var storeAs = "forum";
+                var uploadPath = "http://gangwan-app.oss-cn-hangzhou.aliyuncs.com/" + storeAs;
+                /*将这段字符串存到数据库即可*/
+                var divId = "_attachment";
+                $("#addFile" + divId).show();
+                multipartUploadWithStsCollection(storeAs, file, attachmentId, attachmentFlag, uploadPath, divId, size);
+            }
+        }
+
+    </script>
+
+</head>
+<body >
+<div class="single-form">
+    <div class="container">
+        <form:form id="inputForm" modelAttribute="forum" enctype="multipart/form-data" action="${ctx}/forum/forum/save" method="post" class="form-horizontal layui-form">
+            <form:hidden path="id"/>
+            <form:hidden path="type"/>
+            <form:hidden path="tabType"/>
+            <sys:message content="${message}"/>
+            <div class="form-group layui-row first">
+            </div>
+            <div class="form-group layui-row">
+                <div class="form-group-label"><h2>发帖信息</h2></div>
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label"><span class="require-item">*</span>发帖标题:</label>
+                    <div class="layui-input-block">
+                        <form:input path="title" htmlEscape="false" placeholder="请输入发帖标题" maxlength="30" class="form-control judgment layui-input"/>
+                    </div>
+                </div>
+
+
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label">创建人:</label>
+                    <div class="layui-input-block">
+                        <form:input id="cBName" path="createBy.name" htmlEscape="false" readonly="true" class="form-control  layui-input"/>
+                    </div>
+                </div>
+                <div class="layui-item layui-col-sm6">
+                    <label class="layui-form-label">所属部门:</label>
+                    <div class="layui-input-block">
+                        <form:input id="office" path="office.topCompany" htmlEscape="false" readonly="true" class="form-control  layui-input"/>
+                    </div>
+                </div>
+                <div class="layui-item layui-col-sm12" style="padding-bottom: 20px;">
+                    <label class="layui-form-label"><span class="require-item">*</span>内容:</label>
+                    <div class="layui-input-block">
+                        <form:textarea path="contents" htmlEscape="false"  colspan="3" rows="6"  maxlength="550" class="form-control "/>
+                        <form:hidden id="content" path="content" htmlEscape="false" maxlength="64" class="form-control judgment"/>
+                        <sys:ckeditor replace="contents" uploadPath="/oa/oa"/>
+                    </div>
+                </div>
+            </div>
+
+
+            <!-- fileHandlerFuncName="myCustomHandler" 自定义函数名 -->
+            <!-- attachmentFlag="6" 附件标识 -->
+            <!-- storeAs="wrkReimbursement" 存储路径标识 -->
+            <!-- showOperateArea="false" 是否展示新增按钮,默认true -->
+            <table:attachmentManager
+                    title="附件信息"
+                    addBtnText="添加附件"
+                    baseId="attachment"
+                    attachments="${forum.workAttachments}"
+                    fileHandlerFuncName="insertTitle"
+                    attachmentFlag="0409"
+                    storeAs="forum"
+            />
+
+
+            <div class="form-group layui-row page-end"></div>
+        </form:form>
+    </div>
+</div>
+</body>
+</html>

+ 652 - 0
src/main/webapp/webpage/modules/forum/forumIndex.jsp

@@ -0,0 +1,652 @@
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@ include file="/webpage/include/taglib.jsp"%>
+<html>
+<head>
+    <title>通告管理</title>
+    <meta name="decorator" content="default"/>
+    <%@include file="/webpage/include/treeview.jsp" %>
+
+    <script type="text/javascript" src="${ctxStatic}/layui/layui.js"></script>
+    <link rel='stylesheet' type="text/css" href="${ctxStatic}/layui/css/layui.css"/>
+
+    <style type="text/css">
+        html, body {height: 100%;margin: 0;padding: 0;overflow: hidden;}
+        .ztree {overflow:auto;margin:0 !important;padding:0 !important;}
+        #left .ztreeContainer .ztree {
+            min-width: calc(320px - 32px - 2px) !important;
+            width: 100% !important;
+        }
+
+        body{
+            background-color:transparent;
+            filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#26FFFFFF, endColorstr=#26FFFFFF);
+            color:#ffffff;
+            background-color:rgba(255,255,255,0);
+            height:100%;
+        }
+
+        #content {
+            display: flex;
+            height: 100%;
+            width: 100%;
+            overflow: hidden;
+        }
+
+        #left {
+            width: 280px !important;
+            min-width: 280px;
+            display: flex;
+            flex-direction: column;
+            border-right: 1px solid #eee;
+            background: #fff;
+            padding:0; margin:0;
+            height: 100%;
+        }
+
+        .btn-group {
+            display: none;
+            padding: 8px 10px;
+            background: #f9f9f9;
+            border-bottom: 1px solid #e6e6e6;
+            gap: 8px;
+            flex-shrink: 0;
+        }
+        .btn-group.show {
+            display: flex !important;
+        }
+        .btn-group .btn {
+            padding: 6px 14px;
+            border: 1px solid #ddd;
+            border-radius: 3px;
+            background: #fff;
+            cursor: pointer;
+            font-size: 14px;
+            line-height: 1.5;
+        }
+        .btn-group .btn:hover {
+            background: #2d8cf0;
+            color: #fff;
+            border-color: #2d8cf0;
+        }
+
+        .tab-nav {
+            display: flex;
+            background: #f5f5f5;
+            border-bottom: 1px solid #ddd;
+            flex-shrink: 0;
+        }
+        .tab-nav .tab-item {
+            flex: 1;
+            text-align: center;
+            padding: 10px 0;
+            cursor: pointer;
+            font-weight: 500;
+            color: #666;
+            border: 1px solid #ddd;
+            border-bottom: none;
+            background: #f5f5f5;
+            font-size: 14px;
+        }
+        .tab-nav .tab-item.active {
+            background: #fff;
+            color: #2d8cf0;
+            border-bottom: 2px solid #2d8cf0;
+            font-weight: bold;
+        }
+
+        .ztreeContainer {
+            flex: 1;
+            overflow: hidden;
+            background: #fff;
+            padding:0; margin:0;
+            height: 100%;
+            min-height: 0;
+            position: relative;
+        }
+        .ztreeBox {
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            visibility: hidden;
+            opacity: 0;
+            overflow-y: auto;
+            padding:0; margin:0;
+            transition: opacity 0.1s;
+        }
+        .ztreeBox.show {
+            visibility: visible;
+            opacity: 1;
+        }
+
+        #right {
+            flex: 1;
+            height: 100%;
+            overflow: hidden;
+            background: #fff;
+        }
+        #right .layui-row {
+            height: 100%;
+            width: 100%;
+            position: relative;
+        }
+        #userContent {
+            position: absolute;
+            top: 0; left: 0;
+            width: 100%; height: 100%;
+            border: none;
+        }
+
+        #forumName {
+            pointer-events: auto !important;
+            user-select: text !important;
+            -webkit-user-select: text !important;
+            color: #333 !important;
+            background: #fff !important;
+            caret-color: #333 !important;
+            border: 1px solid #e6e6e6 !important;
+            border-radius: 2px !important;
+            opacity: 1 !important;
+        }
+        #forumName::placeholder { color: #999 !important; opacity: 1 !important; }
+        #forumName:-ms-input-placeholder { color: #999 !important; }
+        #forumName::-moz-placeholder { color: #999 !important; opacity: 1 !important; }
+        #forumName::-webkit-input-placeholder { color: #999 !important; }
+    </style>
+</head>
+<body>
+<div class="wrapper wrapper-content full-width" id="divId" style="height: 100%;">
+    <sys:message content="${message}"/>
+    <div id="content" class="pr full-height full-width">
+
+        <div id="left" class="contentShadow fl contents">
+            <div id="btn-join" class="btn-group show">
+                <button class="btn" onclick="quitForum()">退出论坛</button>
+                <%--<button class="btn" onclick="refreshTree('join')">刷新</button>--%>
+            </div>
+            <div id="btn-create" class="btn-group">
+                <button class="btn" onclick="openCreateForum()">新建论坛</button>
+                <button class="btn" onclick="openEditForum()">编辑论坛</button>
+                <button class="btn" onclick="deleteForum()">删除</button>
+            </div>
+            <div id="btn-all" class="btn-group">
+                <button class="btn" onclick="joinForum()">加入论坛</button>
+                <button class="btn" onclick="applicationDetailsForum()">申请情况</button>
+            </div>
+
+            <div class="tab-nav">
+                <div class="tab-item" data-tab="join">我加入的</div>
+                <div class="tab-item" data-tab="create">我创建的</div>
+                <div class="tab-item" data-tab="all">所有论坛</div>
+            </div>
+
+            <div class="ztreeContainer" style="position: relative;">
+                <div id="tree-join" class="ztree ztreeBox"></div>
+                <div id="tree-create" class="ztree ztreeBox"></div>
+                <div id="tree-all" class="ztree ztreeBox"></div>
+            </div>
+        </div>
+
+        <div id="right" class="fl contents">
+            <div class="layui-row contentShadow full-height tran-bg">
+                <iframe id="userContent" name="userContent" src="${ctx}/forum/forum/list" frameborder="0"></iframe>
+            </div>
+        </div>
+    </div>
+</div>
+
+<script type="text/javascript">
+    // 🔥 核心:从后端接收 tabType,自动切换页面
+    var defaultTabType = ${empty tabType ? 1 : tabType};
+
+    var zTreeInstances = {
+        "tree-join": null,
+        "tree-create": null,
+        "tree-all": null
+    };
+
+    function refresh(){
+        window.location="${ctx}/forum/forum/";
+    }
+
+    // 退出论坛(带确认 + 创建者禁止退出 + 调用后端)
+    function quitForum() {
+        layui.use(['layer'], function(){
+            var layer = layui.layer;
+            var currentTab = $(".tab-item.active").data("tab");
+            var treeId = "tree-" + currentTab;
+            var treeObj = zTreeInstances[treeId];
+            var nodes = treeObj.getSelectedNodes();
+
+            // 1. 必须选中论坛
+            if(!nodes || nodes.length === 0){
+                layer.msg("请先选中要退出的论坛", {icon:7});
+                return;
+            }
+
+            var node = nodes[0];
+            if(node.id === '0'){
+                layer.msg("根节点不能操作", {icon:7});
+                return;
+            }
+
+            // 2. 关键:判断是否是自己创建的论坛 → 禁止退出
+            if (node.createBySelf === true || node.createBySelf === "true") {
+                layer.msg("你是该论坛创建者,无法退出!", {icon:2, time:2500});
+                return;
+            }
+
+            // 3. 弹出确认退出框(修复字体颜色为黑色)
+            layer.confirm(
+                '<div style="color:#333 !important; font-size:14px;">确定要退出论坛【'+ node.name +'】吗?</div>',
+                {
+                    icon: 3,
+                    title: '退出确认',
+                    // 👇 关键:强制设置内容区字体为黑色
+                    success: function(layero){
+                        // 1. 内容区文字强制黑色
+                        layero.find('.layui-layer-content').css({
+                            'color': '#333',
+                            'background-color': '#fff'
+                        });
+                        // 2. 按钮文字也强制黑色(避免被主题影响)
+                        layero.find('.layui-layer-btn0, .layui-layer-btn1').css('color', '#333');
+                    }
+                },
+                function(index){
+                    console.log(node)
+                    // 确认后调用后端退出接口
+                    $.ajax({
+                        url: '${ctx}/forum/forum/quitForumDiscussionById', // 你的退出接口地址
+                        type: 'post',
+                        data: {forumDiscussionId: node.id},
+                        dataType: 'json',
+                        success: function(res){
+                            if(res.code === 0){
+                                layer.msg('退出成功', {icon:1});
+                                refreshTree(currentTab); // 刷新树
+                                $('#userContent').attr("src","${ctx}/forum/forum/list?tabType="+getTabType(currentTab));
+                            }else{
+                                layer.msg(res.msg || '退出失败', {icon:2});
+                            }
+                        },
+                        error: function(){
+                            layer.msg('网络异常,请重试', {icon:2});
+                        }
+                    });
+                    layer.close(index);
+                }
+            );
+        });
+    }
+
+    // 新建论坛
+    function openCreateForum() {
+        layui.use(['layer'], function(){
+            var layer = layui.layer;
+            layer.open({
+                type: 1,
+                title: '新建论坛',
+                area: ['600px', '260px'],
+                scrollbar: false,
+                overflow: 'hidden',
+                content: '<div style="padding:30px;overflow:hidden;">'
+                    + '<input type="text" id="forumName" placeholder="请输入论坛名称" '
+                    + 'style="width:100%;height:50px;padding:0 15px;font-size:16px;color:#333;background:#fff;border:1px solid #ccc;border-radius:4px;caret-color:#333;box-sizing:border-box;">'
+                    + '</div>',
+                btn: ['确认创建', '取消'],
+                btnAlign: 'r',
+                yes: function(index){
+                    var name = $.trim($('#forumName').val());
+                    if (!name) {
+                        layer.msg('请输入论坛名称', { icon: 2, time: 1500 });
+                        $('#forumName').focus();
+                        return false;
+                    }
+
+                    $.ajax({
+                        url: '${ctx}/forum/forum/saveForumDiscussion',
+                        type: 'post',
+                        data: { name: name },
+                        dataType: 'json',
+                        beforeSend: function(){ layer.load(1, {shade: 0.1}); },
+                        success: function(res){
+                            layer.closeAll('loading');
+                            if (res && res.code == 0) {
+                                layer.msg('创建成功', { icon: 1, time: 1500 });
+                                layer.close(index);
+                                var currentTab = $(".tab-item.active").data("tab");
+                                refreshTree(currentTab);
+                                $('#userContent').attr("src","${ctx}/forum/forum/list?tabType="+getTabType(currentTab));
+                            } else {
+                                layer.msg(res.msg || '创建失败', { icon: 2, time: 2000 });
+                            }
+                        },
+                        error: function(){
+                            layer.closeAll('loading');
+                            layer.msg('网络异常,请重试', { icon: 2, time: 2000 });
+                        }
+                    });
+                    return false;
+                },
+                success: function(){
+                    setTimeout(function(){ $('#forumName').focus(); }, 100);
+                }
+            });
+        });
+    }
+
+    // 编辑论坛
+    function openEditForum(){
+        layui.use(['layer'], function(){
+            var layer = layui.layer;
+            var currentTab = $(".tab-item.active").data("tab");
+            var treeId = "tree-"+currentTab;
+            var treeObj = zTreeInstances[treeId];
+            var nodes = treeObj.getSelectedNodes();
+
+            if(!nodes || nodes.length==0){
+                layer.msg("请选中需要编辑的论坛信息",{icon:7});
+                return;
+            }
+
+            var node = nodes[0];
+            if(node.id == '0'){
+                layer.msg("根节点不能编辑",{icon:7});
+                return;
+            }
+
+            layer.open({
+                type: 1,
+                title: '编辑论坛',
+                area: ['600px', '260px'],
+                scrollbar: false,
+                overflow: 'hidden',
+                content: '<div style="padding:30px;overflow:hidden;">'
+                    + '<input type="text" id="editForumName" value="'+node.name+'" '
+                    + 'style="width:100%;height:50px;padding:0 15px;font-size:16px;color:#333;background:#fff;border:1px solid #ccc;border-radius:4px;caret-color:#333;box-sizing:border-box;">'
+                    + '<input type="hidden" id="editForumId" value="'+node.id+'">'
+                    + '</div>',
+                btn: ['保存修改', '取消'],
+                btnAlign: 'r',
+                yes:function(index){
+                    var newName = $.trim($("#editForumName").val());
+                    var forumId = $("#editForumId").val();
+
+                    if(!newName){
+                        layer.msg("请输入论坛名称",{icon:2});
+                        return;
+                    }
+
+                    $.ajax({
+                        url:'${ctx}/forum/forum/updateForumDiscussion',
+                        type:'post',
+                        data:{
+                            id:forumId,
+                            name:newName
+                        },
+                        dataType:'json',
+                        beforeSend:function(){layer.load(1);},
+                        success:function(res){
+                            layer.closeAll('loading');
+                            if(res.code==0){
+                                layer.msg("修改成功",{icon:1});
+                                layer.close(index);
+                                refreshTree(currentTab);
+                            }else{
+                                layer.msg(res.msg||"修改失败",{icon:2});
+                            }
+                        },
+                        error:function(){
+                            layer.closeAll('loading');
+                            layer.msg("网络异常",{icon:2});
+                        }
+                    });
+                },
+                success: function(){
+                    setTimeout(function(){ $('#editForumName').focus(); }, 100);
+                }
+            });
+        });
+    }
+
+    // 删除论坛
+    function deleteForum(){
+        layui.use(['layer'],function(){
+            var layer = layui.layer;
+            var currentTab = $(".tab-item.active").data("tab");
+            var treeId = "tree-"+currentTab;
+            var treeObj = zTreeInstances[treeId];
+            var nodes = treeObj.getSelectedNodes();
+
+            if(!nodes||nodes.length==0){
+                layer.msg("请选中要删除的论坛",{icon:7});
+                return;
+            }
+
+            var node = nodes[0];
+            if(node.id=='0'){
+                layer.msg("根节点不能删除",{icon:7});
+                return;
+            }
+
+            layer.confirm(
+                '<div style="color:#333 !important; font-size:14px;">确定要删除【'+node.name+'】吗?</div>',
+                {
+                    icon: 3,
+                    title: '提示',
+                    success: function(layero){
+                        layero.find('.layui-layer-content').css('color','#333');
+                    }
+                },
+                function(index){
+                    $.ajax({
+                        url:'${ctx}/forum/forum/deleteForumDiscussion',
+                        type:'post',
+                        data:{id:node.id},
+                        dataType:'json',
+                        success:function(res){
+                            if(res.code==0){
+                                layer.msg("删除成功",{icon:1});
+                                refreshTree(currentTab);
+                            }else{
+                                layer.msg(res.msg||"删除失败");
+                            }
+                        },
+                        error:function(){
+                            layer.msg("网络异常,请重试",{icon:2});
+                        }
+                    });
+                    layer.close(index);
+                }
+            );
+        });
+    }
+
+    // 加入论坛
+    function joinForum() {
+        layui.use(['layer'], function(){
+            var layer = layui.layer;
+            var currentTab = $(".tab-item.active").data("tab");
+            var treeId = "tree-"+currentTab;
+            var treeObj = zTreeInstances[treeId];
+            var nodes = treeObj.getSelectedNodes();
+
+            // 必须选中论坛
+            if(!nodes || nodes.length === 0){
+                layer.msg("请先选中要加入的论坛", {icon:7});
+                return;
+            }
+
+            var node = nodes[0];
+            if(node.id === '0'){
+                layer.msg("根节点不能操作", {icon:7});
+                return;
+            }
+
+            // 已经是自己创建的 → 无需加入
+            if (node.createBySelf === true || node.createBySelf === "true") {
+                layer.msg("你是该论坛创建者,已默认加入", {icon:7});
+                return;
+            }
+
+            // 确认框
+            layer.confirm(
+                '<div style="color:#333 !important; font-size:14px;">确定要加入论坛【'+node.name+'】吗?</div>',
+                {
+                    icon: 3,
+                    title: '加入确认',
+                    success: function(layero){
+                        layero.find('.layui-layer-content').css({
+                            'color':'#333',
+                            'background-color':'#fff'
+                        });
+                    }
+                },
+                function(index){
+                    // 调用加入接口
+                    $.ajax({
+                        url: '${ctx}/forum/forum/joinForum',
+                        type: 'post',
+                        data: {forumDiscussionId: node.id},
+                        dataType: 'json',
+                        beforeSend: function(){ layer.load(1, {shade:0.1}); },
+                        success: function(res){
+                            layer.closeAll('loading');
+                            if(res.code == 0){
+                                layer.msg("加入成功", {icon:1});
+                                refreshTree(currentTab); // 刷新树
+                            }else{
+                                layer.msg(res.msg || "加入失败", {icon:2});
+                            }
+                        },
+                        error: function(){
+                            layer.closeAll('loading');
+                            layer.msg("网络异常,请重试", {icon:2});
+                        }
+                    });
+                    layer.close(index);
+                }
+            );
+        });
+    }
+
+    // 查看【我的申请情况】(无需选中树,直接弹出页面)
+    function applicationDetailsForum() {
+        layui.use(['layer'], function(){
+            var layer = layui.layer;
+
+            // 直接弹出页面,不需要选中任何节点
+            layer.open({
+                type: 2,   // 弹出 iframe
+                title: '我的申请情况',
+                area: ['90%', '85%'],  // 大小
+                maxmin: true,
+                content: '${ctx}/forum/forum/myApplyList', // 后端地址
+                scrollbar: false
+            });
+        });
+    }
+
+
+    // tree 样式
+    function addDiyDom(treeId, treeNode) {
+        var spaceWidth = 15;
+        var switchObj = $("#" + treeNode.tId + "_switch"),
+            icoObj = $("#" + treeNode.tId + "_ico");
+        switchObj.remove();
+        icoObj.before(switchObj);
+        if (treeNode.level > 0) {
+            var spaceStr = "<span style='display: inline-block;width:" + (spaceWidth * treeNode.level)+ "px'></span>";
+            switchObj.before(spaceStr);
+        }
+    }
+
+    var setting = {
+        data:{simpleData:{enable:true}},
+        callback:{
+            onClick:function(event, treeId, treeNode){
+                var type = treeNode.id == '0' ? '' : treeNode.id;
+                var currentTab = $(".tab-item.active").data("tab");
+                $('#userContent').attr("src","${ctx}/forum/forum/list?type="+type+"&tabType="+getTabType(currentTab)+"&"+new Date().getTime());
+            }
+        },
+        view:{showLine: false,showIcon: false,addDiyDom: addDiyDom}
+    };
+
+    // tab 类型映射
+    function getTabType(tabKey){
+        if(tabKey === "join") return 1;
+        if(tabKey === "create") return 2;
+        if(tabKey === "all") return 3;
+        return 1;
+    }
+
+    // 页面初始化(支持 tabType 自动跳转)
+    $(function(){
+        var targetTabKey = "join";
+
+        if(defaultTabType == 2){
+            targetTabKey = "create";
+        }else if(defaultTabType == 3){
+            targetTabKey = "all";
+        }
+
+        // 自动激活 tab
+        $('.tab-item').removeClass('active');
+        $('.tab-item[data-tab="'+targetTabKey+'"]').addClass('active');
+        $('.ztreeBox').removeClass('show');
+        $('#tree-'+targetTabKey).addClass('show');
+        $('.btn-group').removeClass('show');
+        $('#btn-'+targetTabKey).addClass('show');
+
+        // 加载内容
+        var tabType = getTabType(targetTabKey);
+        loadTabContent(tabType);
+        setTimeout(()=>refreshTree(targetTabKey),50);
+
+        // 点击切换
+        $('.tab-item').on('click', function(){
+            var tabKey = $(this).data('tab');
+            $('.tab-item').removeClass('active');
+            $(this).addClass('active');
+            $('.ztreeBox').removeClass('show');
+            $('#tree-'+tabKey).addClass('show');
+            $('.btn-group').removeClass('show');
+            $('#btn-'+tabKey).addClass('show');
+
+            var t = getTabType(tabKey);
+            loadTabContent(t);
+            setTimeout(()=>refreshTree(tabKey),50);
+        });
+    });
+
+    // 加载右侧列表
+    function loadTabContent(tabType){
+        $('#userContent').attr("src", "${ctx}/forum/forum/list?tabType=" + tabType + "&" + new Date().getTime());
+    }
+
+    // 刷新树
+    function refreshTree(type){
+        var treeId = "tree-" + type;
+        var tabType = getTabType(type);
+
+        if(zTreeInstances[treeId]){
+            zTreeInstances[treeId].destroy();
+            zTreeInstances[treeId] = null;
+        }
+        $("#" + treeId).empty();
+
+        $.getJSON("${ctx}/forum/forum/treeDataNotify?tabType=" + tabType + "&" + new Date().getTime(), function(data){
+            zTreeInstances[treeId] = $.fn.zTree.init($("#" + treeId), setting, data);
+            var treeObj = zTreeInstances[treeId];
+            var nodes = treeObj.getNodes();
+            if (nodes.length > 0) {
+                treeObj.expandNode(nodes[0], true);
+            }
+        });
+    }
+</script>
+</body>
+</html>

+ 684 - 0
src/main/webapp/webpage/modules/forum/forumList.jsp

@@ -0,0 +1,684 @@
+<%@ 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">
+
+		$(function () {
+			$(".btn btn-white btn-sm").bind("click",function () {
+
+            })
+        });
+
+        $(document).ready(function() {
+            //搜索框收放
+            $('#moresee').click(function(){
+                if($('#moresees').is(':visible'))
+                {
+                    $('#moresees').slideUp(0,resizeListWindow1);
+                    $('#moresee i').removeClass("glyphicon glyphicon-menu-up").addClass("glyphicon glyphicon-menu-down");
+                }else{
+                    $('#moresees').slideDown(0,resizeListWindow1);
+                    $('#moresee i').removeClass("glyphicon glyphicon-menu-down").addClass("glyphicon glyphicon-menu-up");
+                }
+            });
+            laydate.render({
+                elem: '#createStartDate', //目标元素。由于laydate.js封装了一个轻量级的选择器引擎,因此elem还允许你传入class、tag但必须按照这种方式 '#id .class'
+                event: 'focus', //响应事件。如果没有传入event,则按照默认的click
+                type : 'date'
+            });
+            laydate.render({
+                elem: '#createEndDate', //目标元素。由于laydate.js封装了一个轻量级的选择器引擎,因此elem还允许你传入class、tag但必须按照这种方式 '#id .class'
+                event: 'focus', //响应事件。如果没有传入event,则按照默认的click
+                type : 'date'
+            });
+        });
+
+        function openDialog(title,url,width,height,target) {
+			var type = '${type}'
+			// 👇 这里加判断:type 为空就提示,并且直接返回,不打开弹窗
+			if(!type || type == null || type == ''){
+				top.layer.msg('请先选择左侧需要添加帖子的论坛', {icon: 7, time: 2000});
+				return;
+			}
+
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {//如果是移动端,就使用自适应大小弹窗
+                width = 'auto';
+                height = 'auto';
+            } else {//如果是PC端,根据用户设置的width和height显示。
+
+            }
+
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: title,
+                maxmin: true, //开启最大化最小化按钮
+                content: url,
+                skin: 'two-btns',
+                btn: ['提交', '关闭'],
+                yes: 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
+                    }
+                },
+				cancel: function (index) {
+                }
+            });
+        }
+
+        function openDialogView(title,url,width,height,target) {
+
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {//如果是移动端,就使用自适应大小弹窗
+                width = 'auto';
+                height = 'auto';
+            } else {//如果是PC端,根据用户设置的width和height显示。
+
+            }
+
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: title,
+                maxmin: true, //开启最大化最小化按钮
+                content: url,
+                skin: 'two-btns',
+                btn: [ '关闭'],
+
+				cancel: function (index) {
+                }
+            });
+        }
+
+        function openDialogAdmin(title,url,width,height,target) {
+
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {//如果是移动端,就使用自适应大小弹窗
+                width = 'auto';
+                height = 'auto';
+            } else {//如果是PC端,根据用户设置的width和height显示。
+
+            }
+
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: title,
+                maxmin: true, //开启最大化最小化按钮
+                content: url,
+                skin: 'three-btns',
+                btn: ['提交', '关闭'],
+                btn1: function(index, layero){
+                    var body = top.layer.getChildFrame('body', index);
+                    var iframeWin = layero.find('iframe')[0]; //得到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 openDialogre(title,url,width,height,target,buttons) {
+
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {//如果是移动端,就使用自适应大小弹窗
+                width = 'auto';
+                height = 'auto';
+            } else {//如果是PC端,根据用户设置的width和height显示。
+
+            }
+            var split = buttons.split(",");
+            top.layer.open({
+                type: 2,
+                area: [width, height],
+                title: title,
+                maxmin: true, //开启最大化最小化按钮
+                skin: 'three-btns',
+                content: url,
+                btn: split,
+                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,layero){
+                    if(split.length==2){return}
+                    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(2) ){
+                        // top.layer.close(index);//关闭对话框。
+                        setTimeout(function(){top.layer.close(index)}, 100);//延时0.1秒,对应360 7.1版本bug
+                    }else {
+                        return false;
+                    }
+                },
+                btn3: function (index) {
+                }
+            });
+        }
+
+        function openDialogreModify(title,url,id,width,height,target,buttons) {
+
+            if (navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)) {//如果是移动端,就使用自适应大小弹窗
+                width = 'auto';
+                height = 'auto';
+            } else {//如果是PC端,根据用户设置的width和height显示。
+
+            }
+
+			$.ajax({
+				async: false,
+				url: "${ctx}/forum/forum/getForum?id="+id,
+				dataType: "json",
+				success: function (data) {
+					if(data.success){
+						var split = buttons.split(",");
+						top.layer.open({
+							type: 2,
+							area: [width, height],
+							title: title,
+							maxmin: true, //开启最大化最小化按钮
+							skin: 'three-btns',
+							content: url,
+							btn: split,
+							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,layero){
+								if(split.length==2){return}
+								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(2) ){
+									// top.layer.close(index);//关闭对话框。
+									setTimeout(function(){top.layer.close(index)}, 100);//延时0.1秒,对应360 7.1版本bug
+								}else {
+									return false;
+								}
+							},
+							btn3: function (index) {
+							}
+						});
+					}else{
+						top.layer.msg("该帖子信息已删除!", {icon: 0});
+						window.location.reload();
+					}
+				}
+			});
+
+
+        }
+
+
+		//打开对话框(查看)
+		function openDialogListView(title,url,id,width,height){
+
+
+			if(navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)){//如果是移动端,就使用自适应大小弹窗
+				width='auto';
+				height='auto';
+			}else{//如果是PC端,根据用户设置的width和height显示。
+
+			}
+			$.ajax({
+				async: false,
+				url: "${ctx}/forum/forum/getForum?id="+id,
+				dataType: "json",
+				success: function (data) {
+					if(data.success){
+						top.layer.open({
+							type: 2,
+							skin: 'one-btn',
+							area: [width, height],
+							title: title,
+							maxmin: true, //开启最大化最小化按钮
+							content: url ,
+							btn: ['关闭'],
+							cancel: function(index){
+							}
+						});
+					}else{
+						top.layer.msg("该帖子信息已删除!", {icon: 0});
+						window.location.reload();
+					}
+				}
+			});
+
+		}
+	</script>
+	<script>
+
+		function notifyDialogre(title,url,width,height,target){
+			if(navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)){//如果是移动端,就使用自适应大小弹窗
+				width='auto';
+				height='auto';
+			}else{//如果是PC端,根据用户设置的width和height显示。
+
+			}
+			top.layer.open({
+				type: 2,
+				area: [width, height],
+				title: title,
+				skin:"three-btns",
+				maxmin: true, //开启最大化最小化按钮
+				content: url ,
+				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,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(2) ){
+						top.layer.close(index);//关闭对话框。
+						setTimeout(function(){top.layer.close(index)}, 100);//延时0.1秒,对应360 7.1版本bug
+					}
+					return false;
+				},
+				btn3: function(index){
+				}
+			});
+
+		}
+
+
+		function openDiscussionUserDialogViewPre(title,url,width,height,type){
+
+			// 👇 这里加判断:type 为空就提示,并且直接返回,不打开弹窗
+			if(!type || type == null || type == ''){
+				top.layer.msg('请先选择左侧需要添加人员的论坛', {icon: 7, time: 2000});
+				return;
+			}
+
+			if(navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)){//如果是移动端,就使用自适应大小弹窗
+				width='auto';
+				height='auto';
+			}else{//如果是PC端,根据用户设置的width和height显示。
+
+			}
+			top.layer.open({
+				type: 2,
+				area: [width, height],
+				title: title,
+				maxmin: true, //开启最大化最小化按钮
+				content: url ,
+				btn: ['关闭'],
+				btn1: function(index){
+					top.layer.close(index);
+					$.ajax({
+						type:'post',
+						url:realPath + '/a/previewController/deleteUrl',
+						success:function(data){
+						}
+					})
+				},
+				end:function(){
+					$.ajax({
+						type:'post',
+						url:realPath + '/a/previewController/deleteUrl',
+						success:function(data){
+						}
+					})
+				}
+			});
+		}
+
+
+		function sortOrRefresh(){//刷新或者排序,页码不清零
+
+			$("#searchForm").submit();
+			return false;
+		}
+
+		// 列表里点击【申请加入】按钮(专用方法)
+		function joinForumFromList(forumDiscussionId, forumName) {
+			layui.use(['layer'], function(){
+				var layer = layui.layer;
+
+				// 确认弹窗
+				layer.confirm(
+						'<div style="color:#333 !important; font-size:14px;">确定要加入论坛【'+ forumName +'】吗?</div>',
+						{
+							icon: 3,
+							title: '加入确认',
+							success: function(layero){
+								layero.find('.layui-layer-content').css({
+									'color':'#333',
+									'background-color':'#fff'
+								});
+							}
+						},
+						function(index){
+							// AJAX 请求加入论坛
+							$.ajax({
+								url: '${ctx}/forum/forum/joinForum',
+								type: 'post',
+								data: {
+									forumDiscussionId: forumDiscussionId  // 传给后端
+								},
+								dataType: 'json',
+								beforeSend: function(){
+									layer.load(1, {shade: 0.1});
+								},
+								success: function(res){
+									layer.closeAll('loading');
+									// 根据后端返回的 MAP 提示
+									if(res.code == 0){
+										layer.msg('已提交加入申请,需要论坛发起人审核同意', {icon:1});
+										// 可选:刷新左侧树
+										try {
+											var currentTab = $(".tab-item.active").data("tab");
+											refreshTree(currentTab);
+										} catch (e) {}
+									} else {
+										layer.msg(res.msg || '申请加入失败', {icon:2});
+									}
+								},
+								error: function(){
+									layer.closeAll('loading');
+									layer.msg('网络异常,请重试', {icon:2});
+								}
+							});
+							layer.close(index);
+						}
+				);
+			});
+		}
+
+	</script>
+	<style>
+		body{
+			background-color:transparent;
+			filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#26FFFFFF, endColorstr=#26FFFFFF);
+			color:#ffffff;
+			background-color:rgba(255,255,255,0);
+			height:100%;
+		}
+	</style>
+</head>
+<body>
+<div class="wrapper wrapper-content">
+	<sys:message content="${message}"/>
+	<div class="layui-row">
+		<div class="full-width fl">
+			<div class="contentShadow layui-row" id="queryDiv">
+
+			<form:form id="searchForm" modelAttribute="forum" action="${ctx}/forum/forum/list?tabType=${tabType}" 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="1"/>--%>
+			<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="title" htmlEscape="false" maxlength="200"  class=" form-control layui-input" />
+						</div>
+					</div>
+
+					<div class="layui-item query athird">
+						<label class="layui-form-label">帖子内容:</label>
+						<div class="layui-input-block with-icon">
+							<form:input path="content" htmlEscape="false" maxlength="200"  class=" form-control layui-input"/>
+						</div>
+					</div>
+
+					<div class="layui-item athird">
+						<div class="input-group">
+							<a href="#" id="moresee"><i class="glyphicon glyphicon-menu-down"></i></a>
+							<div class="layui-btn-group search-spacing">
+								<button id="searchQuery" class="layui-btn layui-btn-sm  layui-bg-blue" onclick="search()">查询</button>
+								<button id="searchReset" class="layui-btn layui-btn-sm  " onclick="resetSearch()">重置</button>
+							</div>
+						</div>
+					</div>
+					<div style="    clear:both;"></div>
+				</div>
+				<div id="moresees" style="clear:both;display:none;">
+
+					<div class="layui-item query athird">
+						<label class="layui-form-label">创建日期:</label>
+						<div class="layui-input-block readOnlyFFF">
+							<input id="createStartDate" name="createStartDate" type="text" readonly="readonly" maxlength="20" class="laydate-icondate form-control layer-date layui-input laydate-icon query-group"
+								   value="<fmt:formatDate value="${forum.createStartDate}" pattern="yyyy-MM-dd"/>"/>
+							</input>
+							<span class="group-sep">-</span>
+							<input id="createEndDate" name="createEndDate" type="text" readonly="readonly" maxlength="20" class="laydate-icondate form-control layer-date layui-input laydate-icon query-group"
+								   value="<fmt:formatDate value="${forum.createEndDate}" pattern="yyyy-MM-dd"/>"/>
+							</input>
+						</div>
+					</div>
+
+					<div class="layui-item query athird">
+						<label class="layui-form-label">创建人:</label>
+						<div class="layui-input-block with-icon">
+							<form:input path="createBy.name" htmlEscape="false" maxlength="200"  class=" form-control layui-input"/>
+						</div>
+					</div>
+
+
+					<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="forum:add">
+							<c:if test="${tabType == 2 || tabType == 1}">
+								<%--此处添加一个添加成员的弹出框--%>
+								<table:addRow label="新增" url="${ctx}/forum/forum/form?type=${type}&tabType=${tabType}" title="通知" height="95%;" width="95%;"></table:addRow><!-- 增加按钮 -->
+							</c:if>
+							<c:if test="${tabType == 2}">
+								<%--此处添加一个添加成员的弹出框--%>
+								<a href="javascript:void(0)" onclick="openDiscussionUserDialogViewPre('论坛成员管理', '${ctx}/forum/forum/formDiscussionUser?id=${type}&type=${type}','95%', '95%','${type}')" class="layui-btn layui-btn-sm layui-btn-orange" > 添加成员</a>
+							</c:if>
+						</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 }
+            ,elem: '#contentTable'
+            ,page: false
+            ,cols: [[
+                // {checkbox: true, fixed: true},
+                {field:'index',align:'center',  width:40,title: '序号'}
+				,{field:'title',align:'center', title: '标题', minWidth:150,templet:function(d){
+						var tabType = ${empty tabType ? '' : tabType};
+						var xml = "";
+						if(tabType === 3){
+							xml = "<span title='"+ d.title +"'>" + d.title + "</span>";
+						}else{
+							xml = "<a class=\"attention-info\" href=\"javascript:void(0)\" onclick=\"openDialogListView('查看帖子', '${ctx}/forum/forum/form?id=" + d.id + "&view=view','" + d.id + "','95%','95%')\">" +
+									"<span title=" + d.title + ">" + d.title + "</span></a>";
+						}
+						return xml;
+					}}
+                ,{field:'content',align:'center', title: '内容', minWidth:200,templet:function(d){
+                    return "<span title='"+ d.content +"'>" + d.content + "</span>";
+                }}
+                ,{field:'forumDiscussionName', align:'center',title: '所属论坛', width:160}
+                ,{field:'createBy', align:'center',title: '创建人', width:80,templet:function(d){
+                        return "<span title='"+ d.createBy +"'>" + d.createBy + "</span>";
+                    }}
+                ,{field:'tmdcreateDate', align:'center',title: '创建时间',width:150,templet:function(d){
+						return "<span title='"+ d.createDate +"'>" + d.tmdcreateDate + "</span>";
+					}}
+                ,{align:'center',title:"操作",width:130,templet:function(d){
+                        ////对操作进行初始化
+                        var xml = "<div class=\"layui-btn-group\">";
+						var tabType = ${empty tabType ? '' : tabType};
+
+						if(tabType === 2 || tabType === 1){
+							if(d.canedit != undefined && d.canedit == "1"){
+								xml += "<a href=\"javascript:void(0)\" onclick=\"openDialog('修改帖子', '${ctx}/forum/forum/form?id="+ d.id +"','95%', '95%')\"   class=\"layui-btn layui-btn-xs  layui-bg-green\"> 修改</a>";
+								xml +="<a href=\"${ctx}/forum/forum/logicDelete?id=" + d.id+"\" onclick=\"return confirmx('确认要删除该帖子吗?', this.href)\"   class=\"layui-btn layui-btn-xs layui-bg-red\"> 删除</a>";
+							}else{
+								xml += "<a href=\"javascript:void(0)\" onclick=\"openDialogView('查看帖子', '${ctx}/forum/forum/form?id=" + d.id + "&view=view','95%', '95%')\"   class=\"layui-btn layui-btn-xs \"> 详情</a>";
+							}
+							if(d.flagAdmin != undefined && d.flagAdmin == "1")
+								xml += "<a href=\"javascript:void(0)\" onclick=\"openDialogAdmin('修改帖子', '${ctx}/forum/forum/adminForm?id="+ d.id +"','95%', '95%')\"   class=\"layui-btn layui-btn-xs layui-bg-green\"> 修改</a>";
+
+						}else if(tabType === 1){
+
+						}else if(tabType === 3){
+
+							xml +="<a href=\"javascript:;\" onclick=\"joinForumFromList('"+d.forumDiscussionId+"','"+d.forumDiscussionName+"')\" class=\"layui-btn layui-btn-xs\">申请加入</a>";
+
+						}
+                        xml+="</div>"
+                            return xml;
+                    }}
+            ]]
+            ,data: [
+                <c:if test="${ not empty page.list}">
+                <c:forEach items="${page.list}" var="forum" varStatus="index">
+                <c:if test="${index.index != 0}">,</c:if>
+                {
+                    "index":"${index.index+1}"
+                    ,"id":"${forum.id}"
+                    ,"type":"${forum.type}"
+                    ,"number":"${forum.number}"
+                    ,"forumDiscussionName":"${forum.forumDiscussionName}"
+                    ,"forumDiscussionId":"${forum.forumDiscussionId}"
+                    ,"title":"<c:out value="${forum.title}" escapeXml="true"/>"
+                    ,"type":"${fns:getMainDictLabel(forum.type, 'oa_notify_type', '')}"
+                    ,"content":"<c:out value="${forum.content}" escapeXml="true"/>"
+    				,"startDate":"<fmt:formatDate value="${forum.startDate}" pattern="yyyy-MM-dd HH:mm:ss"/>"
+            		,"endDate":"<fmt:formatDate value="${forum.endDate}" pattern="yyyy-MM-dd HH:mm:ss"/>"
+                    ,"vtatus":"${forum.readNum} / ${forum.readNum + forum.unReadNum}"
+                    ,"createBy":"${forum.createBy.name}"
+                    ,"createDate":"<fmt:formatDate value="${forum.createDate}" pattern="yyyy-MM-dd HH:mm:ss"/>"
+                    ,"tmdcreateDate":"<fmt:formatDate value="${forum.createDate}" pattern="yyyy-MM-dd"/>"
+                    ,"procId":"${forum.processInstanceId}"
+                    ,"referenceNumber":"${forum.referenceNumber}"
+					,"notifyFlag":"${forum.notifyFlag}"
+					,"notifyId":"${forum.notifyId}"
+
+					,"canedit": <c:choose><c:when test="${fns:getUser().id == forum.createBy.id}">"1"</c:when><c:otherwise>"0"</c:otherwise></c:choose>
+					, "candelete": <c:choose><c:when test="${fns:getUser().id == forum.createBy.id}">"1"</c:when><c:otherwise>"0"</c:otherwise></c:choose>
+
+                }
+                </c:forEach>
+                </c:if>
+            ]
+            // ,even: true
+            // ,height: 315
+        });
+
+    })
+
+    resizeListTable();
+</script>
+<script>
+    resizeListWindow1();
+    $(window).resize(function(){
+        resizeListWindow1();
+    });
+</script>
+</body>
+</html>

+ 210 - 0
src/main/webapp/webpage/modules/forum/forumUsersForm.jsp

@@ -0,0 +1,210 @@
+<%@ 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}/helloweba_editable-select/jquery.editable-select.min.js"></script>
+	<link rel='stylesheet' type="text/css" href="${ctxStatic}/helloweba_editable-select/jquery.editable-select.min.css"/>
+	<script type="text/javascript">
+		var validateForm;
+		function doSubmit(){//回调函数,在编辑和保存动作时,供openDialog调用提交表单。
+		  if(validateForm.form()){
+			  $("#inputForm").submit();
+			  return true;
+		  }
+		  return false;
+		}
+		$(document).ready(function() {
+			validateForm = $("#inputForm").validate({
+				submitHandler: function(form){
+					loading('正在提交,请稍等...');
+					form.submit();
+				},
+				errorContainer: "#messageBox",
+				errorPlacement: function(error, element) {
+					$("#messageBox").text("输入有误,请先更正。");
+					if (element.is(":checkbox")||element.is(":radio")||element.parent().is(".input-append")){
+						error.appendTo(element.parent().parent());
+					} else {
+						error.insertAfter(element);
+					}
+				}
+			});
+		});
+
+		function changeUser(ids,names) {
+		    var forumId = $("#id").val();
+            $.ajax({
+                type:'POST',
+                dataType:'json',
+                url:'${ctx}/forum/forum/getForumDiscussionUsers',
+                data:{"ids":ids,"forumId":forumId},
+                cache:false,
+                success: function(data) {
+                    var str = "";
+                    var userIds = $("#userIds").val();
+                    var msgInfo = "";
+                    for (var i=0; i<data.length; i++) {
+                        var msg = data[i].msg;
+                        if(msg == "del") {
+                            var id = data[i].id;
+                            $("#delFlag"+id).val("正常");
+                            $("#del"+id).css("display","inline-block");
+                        } else if (msg == "msg") {
+                            var id = data[i].id;
+                            var name = data[i].name;
+                            var office = data[i].officeId;
+                            var mobile = data[i].mobile;
+                            userIds += id + ",";
+                            str += '<tr id="'+id+'">' +
+
+                                '<td>' +
+                                name +
+                                '</td>' +
+                                '<td>' +
+                                office +
+                                '</td>' +
+
+                                '<td>' +
+                                mobile +
+                                '</td>' +
+
+                                '<td style="padding: 0px">' +
+                                '<input id="delFlag'+id+'" name="delFlag" type="text"  readonly="true" value="正常" class="form-control layui-input"/>' +
+                                '</td>' +
+                                '<td>' +
+                                '<span id="del'+id+'" onclick="delRow(this,\''+id+'\')" title="移除" class="op-btn op-btn-delete"><i class="fa fa-trash"></i>&nbsp;移除</span>' +
+                                '</td>' +
+                                '</tr>';
+                        } else {
+                            msgInfo = msg;
+                        }
+                    }
+                    $("#usersList").append(str);
+                    if (msgInfo!= null && msgInfo != '' && msgInfo!= undefined){
+                        parent.layer.msg("新增项目成员成功!"+msgInfo,{icon:1});
+                    }else {
+                        parent.layer.msg("新增项目成员成功!",{icon:1});
+                    }
+                },
+                error:function () {
+                    parent.layer.msg("获取用户信息失败!!!",{icon:2});
+                    parent.layer.close(loadingMessage);
+                }
+            });
+        }
+
+        function delRow(obj,id){
+			console.log(id)
+            var forumId = $("#id").val();
+            $.ajax({
+                type:'POST',
+                dataType:'json',
+                url:'${ctx}/forum/forum/removeForumDiscussionUsers',
+                data:{"userId":id,"forumId":forumId},
+                cache:false,
+                success: function(data) {
+                    if (data!= null && data != '' && data!= undefined){
+                        var msg = data.msg;
+                        if (msg){
+                            parent.layer.msg("移除用户成功!!!",{icon:1});
+                        }else {
+                            parent.layer.msg("论坛创建人不能被移除!!!",{icon:2});
+                        }
+                    }else {
+                        parent.layer.msg("移除用户失败!!!",{icon:2});
+                    }
+                },
+                error:function () {
+                    parent.layer.msg("移除用户失败!!!",{icon:2});
+                }
+            });
+		    $("#delFlag"+id).val("移除");
+		    $("#del"+id).css("display","none");
+        }
+        function getSelectUserIds() {
+            return "";
+        }
+	</script>
+</head>
+<body>
+<div class="single-form">
+	<div class="container">
+		<form:form id="inputForm" modelAttribute="forumDiscussion" action="${ctx}/project/projectRecordUsers/save" method="post" class="form-horizontal">
+		<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-sm6">
+					<label class="layui-form-label">论坛名称:</label>
+					<div class="layui-input-block">
+						<input htmlEscape="false" style="background-color: #f1f1f1" readonly="true" maxlength="30" class="form-control required layui-input"
+							   value="${forumDiscussion.name}"/>
+					</div>
+				</div>
+
+
+			</div>
+
+	<div class="form-group layui-row">
+		<div class="form-group-label"><h2>成员明细</h2></div>
+		<div class="layui-item nav-btns">
+			<sys:inquiretreeselectusers id="members" name="projectMembers" value="${forumDiscussion.memberIds}" labelName="memberNameStr" labelValue="${forumDiscussion.memberNameStr}"
+								 title="用户" url="/sys/office/treeDataAll?type=3" checked="true" cssClass="form-control required" allowClear="true" notAllowSelectParent="true"/>
+		</div>
+		<div class="layui-item layui-col-xs12 form-table-container" >
+			<table  class="table table-bordered table-condensed no-bottom-margin details">
+				<thead>
+				<tr>
+					<th>姓名</th>
+					<th>部门</th>
+					<th>手机号</th>
+					<th width="80px;">状态</th>
+					<th>操作</th>
+				</tr>
+				</thead>
+				<tbody id="usersList">
+				<c:if test="${not empty users}">
+					<c:forEach items="${users}" var="user">
+						<tr id="${user.id}">
+							<td>
+									${user.name}
+							</td>
+							<td>
+									${user.office.name}
+							</td>
+							<td>
+									${user.mobile}
+							</td>
+							<td style="padding:0px;">
+								<c:choose>
+									<c:when test="${user.delFlag == 0}">
+										<input id="delFlag${user.id}" name="delFlag" type="text"  readonly="true" value="正常" class="form-control layui-input"/>
+									</c:when>
+									<c:otherwise>
+										<input id="delFlag${user.id}" name="delFlag" type="text"  readonly="true" value="移除" class="form-control layui-input"/>
+									</c:otherwise>
+								</c:choose>
+							</td>
+							<td>
+								<c:if test="${user.delFlag == 0}">
+									<span id="del${user.id}" onclick="delRow(this,'${user.id}')" title="移除" class="op-btn op-btn-delete"><i class="fa fa-trash"></i>&nbsp;移除</span>
+								</c:if>
+								<c:if test="${user.delFlag != 0}">
+									<span id="del${user.id}" onclick="delRow(this,'${user.id}')" title="移除" style="display: none;" class="op-btn op-btn-delete"><i class="fa fa-trash"></i>&nbsp;移除</span>
+								</c:if>
+
+							</td>
+						</tr>
+					</c:forEach>
+				</c:if>
+				</tbody>
+			</table>
+		</div>
+		<div class="form-group layui-row page-end"></div>
+	</div>
+	</form:form>
+	</div>
+</div>
+</body>
+</html>

+ 357 - 0
src/main/webapp/webpage/modules/forum/forumView.jsp

@@ -0,0 +1,357 @@
+<%@ 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>
+        // 评论分页配置
+        const COMMENT_PAGE_SIZE = 6; // 每页最多6条
+        let currentCommentPage = 1; // 当前页码
+        let allCommentList = []; // 全部评论数据
+        let totalCommentPages = 0; // 总页数
+
+        // 删除评论(局部刷新)
+        function deleteComment(id) {
+            $.ajax({
+                type:"post",
+                url:'${ctx}/forum/forum/deleteComment',
+                data:{"id":id},
+                dataType:"json",
+                success:function(data){
+                    if(data.success) {
+                        top.layer.msg("删除成功!", {icon: 1});
+                        loadCommentList();
+                    }else {
+                        top.layer.msg("删除失败!", {icon: 0});
+                    }
+                }
+            })
+        }
+
+        // 发表评论(局部刷新)
+        function submitComment() {
+            var forumId = $("#id").val();
+            var content = $("#commentContent").val();
+            if(undefined != content && null != content && '' != content){
+                $.ajax({
+                    type:"post",
+                    url:'${ctx}/forum/forum/saveComment',
+                    data:{"forumId":forumId,"content":content},
+                    dataType:"json",
+                    success:function(data){
+                        if(data.success) {
+                            top.layer.msg("发表成功!", {icon: 1});
+                            $("#commentContent").val("");
+                            loadCommentList(true);
+                        }else {
+                            top.layer.msg("发表失败!", {icon: 0});
+                        }
+                    }
+                })
+            }
+        }
+
+        // 清空评论输入框
+        function resetComment() {
+            $("#commentContent").val("");
+        }
+
+        // 加载评论列表(核心分页+局部刷新逻辑)
+        function loadCommentList(goToLastPage = false) {
+            $.ajax({
+                type:"get",
+                url:'${ctx}/forum/forum/getCommentList',
+                data:{"forumId":$("#id").val()},
+                dataType:"json",
+                success:function(data){
+                    console.log("进步")
+                    if(data.success) {
+                        allCommentList = data.commentList || [];
+                        const totalCount = allCommentList.length;
+                        totalCommentPages = Math.ceil(totalCount / COMMENT_PAGE_SIZE);
+
+                        if(goToLastPage && totalCommentPages > 0) {
+                            currentCommentPage = totalCommentPages;
+                        }
+
+                        renderCommentPage();
+                        renderCommentPagination();
+                        $("#commentTotalCount").text(totalCount);
+                    } else {
+                        // 接口返回失败,兜底显示初始数据(如果有)
+                        console.error("加载评论失败:", data.msg);
+                    }
+                },
+                error:function(xhr, status, error){
+                    console.error("AJAX请求失败:", error);
+                    top.layer.msg("加载评论失败,请刷新重试", {icon: 0});
+                }
+            })
+        }
+
+        function renderCommentPage() {
+            const $commentContainer = $("#commentListContainer");
+            $commentContainer.empty();
+
+            if(allCommentList.length === 0) {
+                $commentContainer.append('<div style="padding:20px;text-align:center;color:#999;">暂无评论</div>');
+                return;
+            }
+
+            const startIndex = (currentCommentPage - 1) * COMMENT_PAGE_SIZE;
+            const endIndex = startIndex + COMMENT_PAGE_SIZE;
+            const currentPageList = allCommentList.slice(startIndex, endIndex);
+
+            $.each(currentPageList, function(index, comment) {
+                // 1. 拼接删除按钮(放大样式)
+                var deleteHtml = "";
+                if (comment.flag === 1) {
+                    deleteHtml = '<a href="javascript:void(0)" onclick="deleteComment(\'' + comment.id + '\')" style="float:right;margin-right:20px;color:#666;font-size:14px;font-weight:500;">删除</a>';
+                }
+
+                // 2. 按你的要求美化评论HTML
+                var commentHtml =
+                    '<div class="layui-item layui-col-xs12" id="comment' + comment.id + '" style="padding:10px 0;">' +
+                    '<div class="conmment_details">' +
+                    // 用户名:淡蓝色、字体放大
+                    '<span class="comment_name" style="color:#1E9FFF;font-size:16px;font-weight:500;">' + comment.userName + '</span>' +
+                    // 评论内容:缩进、行高加大
+                    '<div class="comment_content" style="margin-left:25px;margin-top:8px;font-size:14px;line-height:1.8;">' + comment.content + '</div>' +
+                    '<div class="del" style="color:#999;font-size:12px;margin-top:5px;">' +
+                    '<span>' + comment.commentDateStr + '</span>' +
+                    deleteHtml +
+                    '</div>' +
+                    '</div>' +
+                    '<hr style="margin:15px 0;border:none;border-top:1px solid #eee;">' +
+                    '</div>';
+
+                $commentContainer.append(commentHtml);
+            });
+        }
+
+        // ====================== 替换结束 ======================
+
+        // 渲染分页控件(纯JS拼接,无JSP冲突)
+        function renderCommentPagination() {
+            const $pagination = $("#commentPagination");
+            $pagination.empty();
+
+            if(totalCommentPages <= 1) {
+                return;
+            }
+
+            let prevDisabled = currentCommentPage === 1 ? 'disabled' : '';
+            let nextDisabled = currentCommentPage === totalCommentPages ? 'disabled' : '';
+
+            let paginationHtml = '<div style="text-align:center;margin:20px 0;">';
+            paginationHtml += '<button class="layui-btn layui-btn-sm layui-btn-primary" id="prevPage" ' + prevDisabled + '>上一页</button>';
+            paginationHtml += '<span style="margin:0 10px;">' + currentCommentPage + ' / ' + totalCommentPages + '</span>';
+            paginationHtml += '<button class="layui-btn layui-btn-sm layui-btn-primary" id="nextPage" ' + nextDisabled + '>下一页</button>';
+            paginationHtml += '</div>';
+
+            $pagination.append(paginationHtml);
+
+            // 绑定分页事件
+            $("#prevPage").click(function() {
+                if(currentCommentPage > 1) {
+                    currentCommentPage--;
+                    renderCommentPage();
+                    renderCommentPagination();
+                }
+            });
+
+            $("#nextPage").click(function() {
+                if(currentCommentPage < totalCommentPages) {
+                    currentCommentPage++;
+                    renderCommentPage();
+                    renderCommentPagination();
+                }
+            });
+        }
+
+        // 访问日志折叠/展开功能
+        $(function() {
+            const MAX_SHOW_ROWS = 5;
+            const $table = $("#viewTable");
+            const $tbody = $("#oa_notify_view");
+            const $allRows = $tbody.find("tr");
+            const totalRows = $allRows.length;
+
+            if (totalRows <= MAX_SHOW_ROWS) {
+                // 行数≤5,不显示按钮,直接加载评论
+                loadCommentList();
+                return;
+            }
+
+            // 隐藏超过5行的日志
+            $allRows.slice(MAX_SHOW_ROWS).hide();
+
+            // 创建全宽底部条
+            const $toggleBar = $(`
+                <div style="
+                    width: 100%;
+                    box-sizing: border-box;
+                    text-align: center;
+                    line-height: 36px;
+                    height: 36px;
+                    background-color: #f5f5f5;
+                    border: 1px solid #ddd;
+                    border-top: none;
+                    border-radius: 0 0 4px 4px;
+                    cursor: pointer;
+                    color: #666;
+                    font-size: 13px;
+                ">展示全部</div>
+            `);
+
+            $table.after($toggleBar);
+
+            // 切换逻辑
+            $toggleBar.on("click", function() {
+                const $hiddenRows = $allRows.slice(MAX_SHOW_ROWS);
+                if ($hiddenRows.is(":hidden")) {
+                    $hiddenRows.show();
+                    $(this).text("收起");
+                } else {
+                    $hiddenRows.hide();
+                    $(this).text("展示全部");
+                }
+            });
+
+            // 页面加载时初始化评论列表(首次加载就分页)
+            loadCommentList();
+        });
+
+    </script>
+</head>
+<body>
+<div class="single-form">
+    <div class="container view-form">
+        <form:form id="inputForm" modelAttribute="forum" class="form-horizontal layui-form">
+        <form:hidden path="id"/>
+        <sys:message content="${message}"/>
+
+        <div class="form-group layui-row first">
+            <div class="form-group-label"><h2>通告信息</h2></div>
+            <div class="layui-item layui-col-sm6">
+                <label class="layui-form-label">通告标题:</label>
+                <div class="layui-input-block">
+                    <input htmlEscape="false" style="background-color: #f1f1f1" readonly="true" maxlength="30" class="form-control required layui-input"
+                           value="${forum.title}"/>
+                </div>
+            </div>
+            <div class="layui-item layui-col-sm6">
+                <label class="layui-form-label">创建日期:</label>
+                <div class="layui-input-block">
+                    <input id="createDate" name="createDate" htmlEscape="false" style="background-color: #f1f1f1" readonly="true"
+                           class="laydate-icondate form-control layer-date layui-input laydate-icon"
+                           value="<fmt:formatDate value="${forum.createDate}" pattern="yyyy-MM-dd HH:mm:ss"/>"/>
+                </div>
+            </div>
+            <div class="layui-item layui-col-sm6">
+                <label class="layui-form-label">创建人:</label>
+                <div class="layui-input-block">
+                    <form:input id="cBName" path="createBy.name" htmlEscape="false" readonly="true" style="background-color: #f1f1f1"
+                                class="form-control  layui-input"/>
+                </div>
+            </div>
+            <div class="layui-item layui-col-sm6">
+                <label class="layui-form-label">所属部门:</label>
+                <div class="layui-input-block">
+                    <form:input id="office" path="office.name" htmlEscape="false" readonly="true" style="background-color: #f1f1f1"
+                                class="form-control  layui-input"/>
+                </div>
+            </div>
+            <div class="layui-item layui-col-sm12" style="padding-bottom: 20px;">
+                <label class="layui-form-label"><span class="require-item">*</span>内容:</label>
+                <div class="layui-input-block">
+                    <div class="wrapForm">
+                        <div class="mask">
+                            <form:textarea path="contents" disabled="true" htmlEscape="false" colspan="3" rows="6" maxlength="550"
+                                           class="form-control "/>
+                            <form:hidden id="content" path="content" htmlEscape="false" maxlength="64"
+                                         class="form-control required"/>
+                            <sys:ckeditorView replace="contents" uploadPath="/oa/oa"/>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+            <c:if test="${!empty forum.workAttachments}">
+                <table:attachmentManager
+                        title="附件信息"
+                        addBtnText="添加附件"
+                        baseId="attachment"
+                        attachments="${forum.workAttachments}"
+                        fileHandlerFuncName="insertTitle"
+                        attachmentFlag="0409"
+                        storeAs="forum"
+                        showOperateArea="false"
+                />
+            </c:if>
+
+            <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 id="viewTable" class="table table-bordered table-condensed details">
+                        <thead>
+                        <tr>
+                            <th width="60px">序号</th>
+                            <th>访问人</th>
+                            <th>首次访问时间</th>
+                            <th>最近访问时间</th>
+                            <th>访问次数</th>
+                        </tr>
+                        </thead>
+                        <tbody id="oa_notify_view">
+                        <c:forEach items="${forumViewList}" var="forumView" varStatus="status">
+                            <tr>
+                                <td>${status.index + 1}</td>
+                                <td>${forumView.userId}</td>
+                                <td>
+                                    <fmt:formatDate value="${forumView.firstVisitTime}" type="both"/>
+                                </td>
+                                <td>
+                                    <fmt:formatDate value="${forumView.lastVisitTime}" type="both"/>
+                                </td>
+                                <td>${forumView.visitCount}</td>
+                            </tr>
+                        </c:forEach>
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+
+            <div class="form-group layui-row">
+                <div class="form-group-label"><h2>发表评论</h2></div>
+                <div class="layui-item layui-col-xs12 with-textarea">
+                    <div class="layui-input-block" style="margin-left:0px;position: relative">
+                        <form:textarea placeholder="请输入评论信息:" path="commentContent" class="form-control required" rows="4" maxlength="255" />
+                    </div>
+                    <div style="float: right;margin-right: 10%">
+                        <br/>
+                        <a href="javascript:void(0)" id="submitComment" class="layui-btn" onclick="submitComment()">发表</a>
+                        <a href="javascript:void(0)" id="resetComment" class="layui-btn layui-btn-primary" onclick="resetComment()">清空</a>
+                    </div>
+                </div>
+            </div>
+
+            <div class="form-group layui-row">
+                <h2>全部评论(<span id="commentTotalCount">${forumCommentCount}</span>条)</h2>
+                <hr>
+                <!-- 评论列表容器(完全由JS渲染,JSP不再渲染初始数据) -->
+                <div id="commentListContainer"></div>
+                <!-- 分页控件容器 -->
+                <div id="commentPagination"></div>
+            </div>
+            <div class="form-group layui-row page-end"></div>
+            </form:form>
+        </div>
+    </div>
+</div>
+</body>
+</html>

+ 2 - 1
src/main/webapp/webpage/modules/ruralprojectrecords/cost/ruralCostProjectRecordsForm.jsp

@@ -190,13 +190,14 @@
         function checkProjectNameSubmit() {
             // 这里换成你的项目名称输入框 ID
             var name = $("#projectName").val();
+            var id = '${ruralProjectRecords.id}';
             var proName = '${ruralProjectRecords.projectName}';
             var isRepeat = false;
 
             $.ajax({
                 type: "POST",
                 url: "${ctx}/ruralProject/ruralProjectRecords/reProjectName",
-                data: { projectName: name },
+                data: { projectName: name,id: id },
                 async: false,    // 关键:同步 → 必须等后端返回才往下走
                 cache: false,
                 success: function (result) {

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

@@ -715,7 +715,7 @@
 						return "<a class=\"attention-info\" title=\"" + d.invoiceNum + "\" href=\"javascript:void(0);\" onclick=\"openDialogListView('查看发票信息', '" + '${ctx}/workinvoiceAll/workInvoiceAll/form?id=' + d.id + '&tabId=1' + '&isSzCloud=' + d.isSzCloud + "','"+ d.id +"', '95%', '95%')\">" + d.invoiceNum + "</a>";
 
 					}}
-				,{field:'widNumber',align:'center', title: '发票号',  width:90,templet:function(d){
+				,{field:'widNumber',align:'center', title: '发票号',  width:180,templet:function(d){
 						return "<span title='"+ d.widNumber +"'>" + d.widNumber + "</span>";
 					}}
 				,{field:'clientName', align:'center',title: '开票单位', minWidth:160,templet:function(d){

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

@@ -790,7 +790,7 @@
 				,{field:'invoiceNum',align:'center', sort:true,title: '发票申请编号', minWidth:130,templet:function(d){
 						return "<a class=\"attention-info\" title=\""+ d.invoiceNum +"\"href=\"javascript:void(0);\" onclick=\"openDialogListView('查看发票信息', '${ctx}/workinvoiceAll/workInvoiceAll/form?id=" + d.id + "&tabId=1','"+ d.id +"','95%', '95%')\">" + d.invoiceNum + "</a>";
 					}}
-				,{field:'widNumber',align:'center', title: '发票号',  width:90,templet:function(d){
+				,{field:'widNumber',align:'center', title: '发票号',  width:180,templet:function(d){
 						return "<span title='"+ d.widNumber +"'>" + d.widNumber + "</span>";
 					}}
 				,{field:'clientName', align:'center',title: '开票单位', minWidth:160,templet:function(d){

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

@@ -834,7 +834,7 @@
 						<%--return "<a class=\"attention-info\" title=\""+ d.invoiceNum +"\"href=\"javascript:void(0);\" onclick=\"openDialogListView('查看发票信息', '${ctx}/workinvoiceAll/workInvoiceAll/form?id=" + d.id + "&tabId=1','"+ d.id +"','95%', '95%')\">" + d.invoiceNum + "</a>";--%>
 						return "<a class=\"attention-info\" title=\"" + d.invoiceNum + "\" href=\"javascript:void(0);\" onclick=\"openDialogListView('查看发票信息', '" + '${ctx}/workinvoiceAll/workInvoiceAll/form?id=' + d.id + '&tabId=1' + '&isSzCloud=' + d.isSzCloud + "','"+ d.id +"', '95%', '95%')\">" + d.invoiceNum + "</a>";
 					}}
-				,{field:'widNumber',align:'center', title: '发票号',  width:90,templet:function(d){
+				,{field:'widNumber',align:'center', title: '发票号',  width:180,templet:function(d){
 						return "<span title='"+ d.widNumber +"'>" + d.widNumber + "</span>";
 					}}
 				,{field:'clientName', align:'center',title: '开票单位', minWidth:160,templet:function(d){