Преглед на файлове

知识库功能初版
代办、通知类型筛选部分功能版

徐滕 преди 2 седмици
родител
ревизия
32784ff477
променени са 60 файла, в които са добавени 3434 реда и са изтрити 226 реда
  1. 30 22
      src/main/java/com/jeeplus/modules/API/sys/RegisterMobileController.java
  2. 65 0
      src/main/java/com/jeeplus/modules/SysMenuDictRelation/dao/SysMenuDictRelationDao.java
  3. 70 0
      src/main/java/com/jeeplus/modules/SysMenuDictRelation/entity/SysMenuDictRelation.java
  4. 133 0
      src/main/java/com/jeeplus/modules/SysMenuDictRelation/service/SysMenuDictRelationService.java
  5. 130 0
      src/main/java/com/jeeplus/modules/SysMenuDictRelation/web/SysMenuDictRelationController.java
  6. 1 1
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseDynamicInfoDao.java
  7. 1 1
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseDynamicValueInfoDao.java
  8. 1 2
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseShareInfoDao.java
  9. 1 1
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseTreeInfoDao.java
  10. 1 1
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseDynamicInfo.java
  11. 1 1
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseDynamicValueInfo.java
  12. 38 7
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseShareInfo.java
  13. 1 1
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseTreeInfo.java
  14. 29 6
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseShareService.java
  15. 2 3
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseTreeService.java
  16. 48 3
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseShareController.java
  17. 3 1
      src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseTreeController.java
  18. 15 0
      src/main/java/com/jeeplus/modules/WorkOssNoteInformInfo/dao/WorkOssNoteInformInfoDao.java
  19. 136 0
      src/main/java/com/jeeplus/modules/WorkOssNoteInformInfo/entity/WorkOssNoteInformInfo.java
  20. 41 0
      src/main/java/com/jeeplus/modules/WorkOssNoteInformInfo/service/WorkOssNoteInformInfoService.java
  21. 77 0
      src/main/java/com/jeeplus/modules/WorkOssNoteInformInfo/web/WorkOssNoteInformInfoController.java
  22. 18 0
      src/main/java/com/jeeplus/modules/ruralprojectrecords/web/RuralProjectRecordsController.java
  23. 7 0
      src/main/java/com/jeeplus/modules/ruralprojectrecords/web/RuralProjectSignatureOldMessageDisposeController.java
  24. 6 7
      src/main/java/com/jeeplus/modules/sys/dao/UserDao.java
  25. 41 5
      src/main/java/com/jeeplus/modules/sys/service/WorkattachmentService.java
  26. 213 2
      src/main/java/com/jeeplus/modules/sys/utils/ALiYunSmsUtil.java
  27. 10 4
      src/main/java/com/jeeplus/modules/sys/utils/UserUtils.java
  28. 26 11
      src/main/java/com/jeeplus/modules/sys/web/LoginController.java
  29. 36 7
      src/main/java/com/jeeplus/modules/sys/web/RegisterController.java
  30. 9 19
      src/main/java/com/jeeplus/modules/syswarning/service/SysWarningService.java
  31. 9 2
      src/main/java/com/jeeplus/modules/workcalendar/service/WorkCalendarTaskService.java
  32. 7 0
      src/main/java/com/jeeplus/modules/workinvoice/dao/WorkInvoiceDao.java
  33. 9 1
      src/main/java/com/jeeplus/modules/workinvoice/entity/WorkInvoice.java
  34. 107 1
      src/main/java/com/jeeplus/modules/workinvoice/service/WorkInvoiceService.java
  35. 6 0
      src/main/java/com/jeeplus/modules/workstaff/dao/WorkStaffCertificateDao.java
  36. 4 0
      src/main/java/com/jeeplus/modules/workstaff/service/WorkStaffCertificateService.java
  37. 263 0
      src/main/resources/mappings/modules/SysMenuDictRelation/SysMenuDictRelationDao.xml
  38. 50 10
      src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseShareInfoDao.xml
  39. 146 0
      src/main/resources/mappings/modules/WorkOssNoteInformInfo/WorkOssNoteInformInfoDao.xml
  40. 16 0
      src/main/resources/mappings/modules/sys/UserDao.xml
  41. 16 2
      src/main/resources/mappings/modules/workinvoice/WorkInvoiceDao.xml
  42. 4 1
      src/main/resources/mappings/modules/workprojectnotify/WorkProjectNotifyDao.xml
  43. 9 0
      src/main/resources/mappings/modules/workstaff/WorkStaffCertificateDao.xml
  44. 289 0
      src/main/webapp/WEB-INF/tags/table/singleAttachmentManager.tag
  45. 0 1
      src/main/webapp/static/oss/ossupload.js
  46. 313 0
      src/main/webapp/webpage/modules/SysMenuDictRelation/sysMenuDictRelationForm.jsp
  47. 196 0
      src/main/webapp/webpage/modules/SysMenuDictRelation/sysMenuDictRelationList.jsp
  48. 82 16
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseIndex.jsp
  49. 127 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareDetail.jsp
  50. 91 38
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareForm.jsp
  51. 123 27
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareList.jsp
  52. 11 0
      src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseTreeForm.jsp
  53. 269 0
      src/main/webapp/webpage/modules/WorkOssNoteInformInfo/workOssNoteInformInfoList.jsp
  54. 1 1
      src/main/webapp/webpage/modules/ruralprojectrecords/ruralProjectRecordsList.jsp
  55. 2 1
      src/main/webapp/webpage/modules/sys/userInfo.jsp
  56. 19 4
      src/main/webapp/webpage/modules/workprojectnotify/workProjectNotifyBacklogListByMine.jsp
  57. 20 4
      src/main/webapp/webpage/modules/workprojectnotify/workProjectNotifyList.jsp
  58. 19 4
      src/main/webapp/webpage/modules/workprojectnotify/workProjectNotifyReadBacklogList.jsp
  59. 18 4
      src/main/webapp/webpage/modules/workprojectnotify/workProjectNotifyReadShowList.jsp
  60. 18 4
      src/main/webapp/webpage/modules/workprojectnotify/workProjectNotifyShowList.jsp

+ 30 - 22
src/main/java/com/jeeplus/modules/API/sys/RegisterMobileController.java

@@ -1,30 +1,18 @@
 package com.jeeplus.modules.API.sys;
 
-import com.easemob.server.example.api.impl.EasemobIMUsers;
-import com.google.common.collect.Lists;
-import com.jeeplus.common.config.Global;
 import com.jeeplus.common.json.AjaxJson;
-import com.jeeplus.common.oss.OSSClientUtil;
-import com.jeeplus.common.utils.FileUtils;
 import com.jeeplus.common.utils.JedisUtils;
 import com.jeeplus.common.utils.RequestUtils;
-import com.jeeplus.common.utils.WordToPic;
 import com.jeeplus.common.web.BaseController;
+import com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo;
+import com.jeeplus.modules.WorkOssNoteInformInfo.service.WorkOssNoteInformInfoService;
 import com.jeeplus.modules.sys.dao.UserDao;
-import com.jeeplus.modules.sys.entity.Dict;
-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.DictService;
 import com.jeeplus.modules.sys.service.SystemService;
 import com.jeeplus.modules.sys.utils.ALiYunSmsUtil;
-import com.jeeplus.modules.sys.utils.DictUtils;
 import com.jeeplus.modules.sys.utils.UserUtils;
-import com.jeeplus.modules.tools.utils.TwoDimensionCode;
 import com.jeeplus.modules.utils.ErrorCode;
-import io.swagger.client.model.Nickname;
-import io.swagger.client.model.RegisterUsers;
-import net.sf.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.transaction.annotation.Transactional;
@@ -35,16 +23,9 @@ import redis.clients.jedis.Jedis;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
+import java.util.Date;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * 注册Controller
@@ -67,6 +48,8 @@ public class RegisterMobileController extends BaseController {
 
     @Autowired
     private UserDao userDao;
+    @Autowired
+    private WorkOssNoteInformInfoService workOssNoteInformInfoService;
 
     @RequestMapping(value = "test" , method=RequestMethod.GET)
     public AjaxJson test(HttpServletRequest request, HttpServletResponse response) {
@@ -338,6 +321,31 @@ public class RegisterMobileController extends BaseController {
             }
 
 
+
+            User user = UserUtils.getUserByMobile(mobile);
+            //获取短信发送内容
+            String smsContent = (String) result.get("smsContent");
+            //获取短信发送结果
+            String message = (String) result.get("message");
+            //将短信发送信息保存到数据库中
+            WorkOssNoteInformInfo workOssNoteInformInfo = new WorkOssNoteInformInfo();
+            workOssNoteInformInfo.setReceiveUserId(user.getId());
+            workOssNoteInformInfo.setSendTime(new Date());
+            workOssNoteInformInfo.setSendContent(smsContent);
+            workOssNoteInformInfo.setPhone(user.getMobile()==null?"":user.getMobile());
+
+            if(200 == statusCode){
+                workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+                workOssNoteInformInfo.setMessage(message);
+                workOssNoteInformInfo.setSmsModule("密码修改");
+            }else{
+                workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+                workOssNoteInformInfo.setMessage(message);
+            }
+            workOssNoteInformInfoService.saveRecord(workOssNoteInformInfo);
+
+
+
         }catch (Exception e){
             logger.info("5");
             j.setSuccess(false);

+ 65 - 0
src/main/java/com/jeeplus/modules/SysMenuDictRelation/dao/SysMenuDictRelationDao.java

@@ -0,0 +1,65 @@
+package com.jeeplus.modules.SysMenuDictRelation.dao;
+
+import com.jeeplus.common.persistence.CrudDao;
+import com.jeeplus.common.persistence.annotation.MyBatisDao;
+import com.jeeplus.modules.SysMenuDictRelation.entity.SysMenuDictRelation;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 菜单与字典值关联关系 DAO
+ * @author: auto
+ * @version: 2026-04-23
+ */
+@MyBatisDao
+public interface SysMenuDictRelationDao extends CrudDao<SysMenuDictRelation> {
+
+    /**
+     * 查询待配置的字典值列表(含已绑定菜单名称)
+     * type_code = 'agenda_project_notify_type' and del_flag = 0
+     */
+    List<Map<String, Object>> findDictValueList();
+
+    /**
+     * 查询所有可选一级菜单(parent_id = '1' and del_flag = 0)
+     */
+    List<Map<String, Object>> findMenuList();
+
+    /**
+     * 根据字典值ID查询已绑定的菜单ID列表
+     * @param dictValueId 字典值ID
+     */
+    List<String> findMenuIdsByDictValueId(@Param("dictValueId") String dictValueId);
+
+    /**
+     * 逻辑删除指定字典值ID的所有绑定关系
+     * @param entity 包含 dictValueId 和 updateBy/updateDate
+     */
+    void deleteByDictValueId(SysMenuDictRelation entity);
+
+    /**
+     * 批量插入绑定关系
+     * @param list 绑定关系列表
+     */
+    void insertBatch(@Param("list") List<SysMenuDictRelation> list);
+
+    /**
+     * 代办页面专用:根据用户菜单ID集合查询有权限的字典値列表
+     * @param menuIds 用户拥有的菜单ID集合
+     */
+    List<Map<String, Object>> findDictValuesByMenuIds(@Param("menuIds") List<String> menuIds);
+
+    /**
+     * 通知页面:查询待配置的字典値列表(含已绑定菜单名称)
+     * type = 'new_project_notify_type' and del_flag = 0
+     */
+    List<Map<String, Object>> findNotifyDictValueList();
+
+    /**
+     * 通知页面专用:根据用户菜单ID集合查询有权限的字典値列表
+     * @param menuIds 用户拥有的菜单ID集合
+     */
+    List<Map<String, Object>> findNotifyDictValuesByMenuIds(@Param("menuIds") List<String> menuIds);
+}

+ 70 - 0
src/main/java/com/jeeplus/modules/SysMenuDictRelation/entity/SysMenuDictRelation.java

@@ -0,0 +1,70 @@
+package com.jeeplus.modules.SysMenuDictRelation.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+
+/**
+ * 菜单与字典值关联关系实体
+ * @author: auto
+ * @version: 2026-04-23
+ */
+public class SysMenuDictRelation extends DataEntity<SysMenuDictRelation> {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 字典值ID */
+    private String dictValueId;
+
+    /** 菜单ID */
+    private String menuId;
+
+    // ---- 非数据库字段,用于展示 ----
+
+    /** 字典标签 */
+    private String dictLabel;
+
+    /** 字典值 */
+    private String dictValue;
+
+    /** 菜单名称(已绑定的菜单名称,逗号分隔) */
+    private String menuNames;
+
+    public String getDictValueId() {
+        return dictValueId;
+    }
+
+    public void setDictValueId(String dictValueId) {
+        this.dictValueId = dictValueId;
+    }
+
+    public String getMenuId() {
+        return menuId;
+    }
+
+    public void setMenuId(String menuId) {
+        this.menuId = menuId;
+    }
+
+    public String getDictLabel() {
+        return dictLabel;
+    }
+
+    public void setDictLabel(String dictLabel) {
+        this.dictLabel = dictLabel;
+    }
+
+    public String getDictValue() {
+        return dictValue;
+    }
+
+    public void setDictValue(String dictValue) {
+        this.dictValue = dictValue;
+    }
+
+    public String getMenuNames() {
+        return menuNames;
+    }
+
+    public void setMenuNames(String menuNames) {
+        this.menuNames = menuNames;
+    }
+}

+ 133 - 0
src/main/java/com/jeeplus/modules/SysMenuDictRelation/service/SysMenuDictRelationService.java

@@ -0,0 +1,133 @@
+package com.jeeplus.modules.SysMenuDictRelation.service;
+
+import com.jeeplus.common.service.CrudService;
+import com.jeeplus.common.utils.IdGen;
+import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.modules.SysMenuDictRelation.dao.SysMenuDictRelationDao;
+import com.jeeplus.modules.SysMenuDictRelation.entity.SysMenuDictRelation;
+import com.jeeplus.modules.sys.entity.Menu;
+import org.apache.shiro.SecurityUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 菜单与字典值关联关系 Service
+ * @author: auto
+ * @version: 2026-04-23
+ */
+@Service
+@Transactional(readOnly = true)
+public class SysMenuDictRelationService extends CrudService<SysMenuDictRelationDao, SysMenuDictRelation> {
+
+    /**
+     * 查询字典值列表(含已绑定菜单名称)
+     */
+    public List<Map<String, Object>> findDictValueList() {
+        return dao.findDictValueList();
+    }
+
+    /**
+     * 查询所有可选一级菜单
+     */
+    public List<Map<String, Object>> findMenuList() {
+        return dao.findMenuList();
+    }
+
+    /**
+     * 根据字典值ID查询已绑定的菜单ID列表
+     */
+    public List<String> findMenuIdsByDictValueId(String dictValueId) {
+        if (StringUtils.isBlank(dictValueId)) {
+            return new ArrayList<>();
+        }
+        return dao.findMenuIdsByDictValueId(dictValueId);
+    }
+
+    /**
+     * 保存/更新绑定关系(先逻辑删除,再批量插入)
+     * @param dictValueId 字典值ID
+     * @param menuIds     菜单ID列表
+     */
+    @Transactional(readOnly = false)
+    public void saveBinding(String dictValueId, List<String> menuIds) {
+        // 逻辑删除原有绑定关系
+        SysMenuDictRelation delEntity = new SysMenuDictRelation();
+        delEntity.setDictValueId(dictValueId);
+        delEntity.preUpdate();
+        dao.deleteByDictValueId(delEntity);
+
+        // 批量插入新绑定关系(去重处理)
+        if (menuIds != null && !menuIds.isEmpty()) {
+            List<SysMenuDictRelation> insertList = new ArrayList<>();
+            for (String menuId : menuIds) {
+                if (StringUtils.isBlank(menuId)) {
+                    continue;
+                }
+                SysMenuDictRelation relation = new SysMenuDictRelation();
+                relation.setId(IdGen.uuid());
+                relation.setDictValueId(dictValueId);
+                relation.setMenuId(menuId);
+                relation.preInsert();
+                insertList.add(relation);
+            }
+            if (!insertList.isEmpty()) {
+                dao.insertBatch(insertList);
+            }
+        }
+    }
+
+    /**
+     * 代办页面专用:根据当前用户权限返回可展示的字典値列表
+     */
+    @SuppressWarnings("unchecked")
+    public List<Map<String, Object>> findDictValuesByCurrentUser() {
+        // 获取当前用户的菜单列表
+        List<Menu> menuList = (List<Menu>) SecurityUtils.getSubject().getSession().getAttribute("menuList");
+        if (menuList == null || menuList.isEmpty()) {
+            return new ArrayList<>();
+        }
+        // 提取所有菜单ID
+        List<String> menuIds = new ArrayList<>();
+        for (Menu menu : menuList) {
+            if (menu != null && StringUtils.isNotBlank(menu.getId())) {
+                menuIds.add(menu.getId());
+            }
+        }
+        if (menuIds.isEmpty()) {
+            return new ArrayList<>();
+        }
+        return dao.findDictValuesByMenuIds(menuIds);
+    }
+
+    /**
+     * 通知页面:查询字典値列表(含已绑定菜单名称)
+     */
+    public List<Map<String, Object>> findNotifyDictValueList() {
+        return dao.findNotifyDictValueList();
+    }
+
+    /**
+     * 通知页面专用:根据当前用户权限返回可展示的字典値列表
+     */
+    @SuppressWarnings("unchecked")
+    public List<Map<String, Object>> findNotifyDictValuesByCurrentUser() {
+        List<Menu> menuList = (List<Menu>) SecurityUtils.getSubject().getSession().getAttribute("menuList");
+        if (menuList == null || menuList.isEmpty()) {
+            return new ArrayList<>();
+        }
+        List<String> menuIds = new ArrayList<>();
+        for (Menu menu : menuList) {
+            if (menu != null && StringUtils.isNotBlank(menu.getId())) {
+                menuIds.add(menu.getId());
+            }
+        }
+        if (menuIds.isEmpty()) {
+            return new ArrayList<>();
+        }
+        return dao.findNotifyDictValuesByMenuIds(menuIds);
+    }
+}

+ 130 - 0
src/main/java/com/jeeplus/modules/SysMenuDictRelation/web/SysMenuDictRelationController.java

@@ -0,0 +1,130 @@
+package com.jeeplus.modules.SysMenuDictRelation.web;
+
+import com.jeeplus.common.web.BaseController;
+import com.jeeplus.modules.SysMenuDictRelation.service.SysMenuDictRelationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 菜单与字典值关联配置 Controller
+ * @author: auto
+ * @version: 2026-04-23
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/sysMenuDictRelation")
+public class SysMenuDictRelationController extends BaseController {
+
+    @Autowired
+    private SysMenuDictRelationService sysMenuDictRelationService;
+
+    /**
+     * 配置管理列表页(代办页面处理 Tab)
+     */
+    @RequestMapping(value = {"list", ""})
+    public String list(Model model) {
+        List<Map<String, Object>> dictValueList = sysMenuDictRelationService.findDictValueList();
+        model.addAttribute("dictValueList", dictValueList);
+        model.addAttribute("activeTab", "agenda");
+        return "modules/SysMenuDictRelation/sysMenuDictRelationList";
+    }
+
+    /**
+     * 配置管理列表页(通知页面处理 Tab)
+     */
+    @RequestMapping(value = "listNotify")
+    public String listNotify(Model model) {
+        List<Map<String, Object>> notifyDictValueList = sysMenuDictRelationService.findNotifyDictValueList();
+        model.addAttribute("notifyDictValueList", notifyDictValueList);
+        model.addAttribute("activeTab", "notify");
+        return "modules/SysMenuDictRelation/sysMenuDictRelationList";
+    }
+
+    /**
+     * 修改绑定弹窗页面
+     */
+    @RequestMapping(value = "form")
+    public String form(@RequestParam String dictValueId,
+                       @RequestParam String dictLabel,
+                       @RequestParam String dictValue,
+                       Model model) {
+        // 查询可选菜单(含一级和二级)
+        List<Map<String, Object>> menuList = sysMenuDictRelationService.findMenuList();
+        // 查询当前字典值已绑定的菜单ID列表
+        List<String> boundMenuIds = sysMenuDictRelationService.findMenuIdsByDictValueId(dictValueId);
+
+        model.addAttribute("dictValueId", dictValueId);
+        model.addAttribute("dictLabel", dictLabel);
+        model.addAttribute("dictValue", dictValue);
+        model.addAttribute("menuList", menuList);
+        model.addAttribute("boundMenuIds", boundMenuIds);
+        return "modules/SysMenuDictRelation/sysMenuDictRelationForm";
+    }
+
+    /**
+     * 保存/更新绑定关系(Ajax)
+     * @param dictValueId 字典值ID
+     * @param menuIds     菜单ID数组(可多个)
+     */
+    @RequestMapping(value = "save")
+    @ResponseBody
+    public Map<String, Object> save(@RequestParam String dictValueId,
+                                    @RequestParam(required = false) String[] menuIds) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            List<String> menuIdList = (menuIds != null) ? Arrays.asList(menuIds) : null;
+            sysMenuDictRelationService.saveBinding(dictValueId, menuIdList);
+            result.put("success", true);
+            result.put("message", "保存成功");
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", "保存失败:" + e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 查询可选菜单(含一级和二级,Ajax)
+     */
+    @RequestMapping(value = "getMenuList")
+    @ResponseBody
+    public List<Map<String, Object>> getMenuList() {
+        return sysMenuDictRelationService.findMenuList();
+    }
+
+    /**
+     * 根据字典值ID查询已绑定菜单ID(Ajax)
+     */
+    @RequestMapping(value = "getBoundMenuIds")
+    @ResponseBody
+    public List<String> getBoundMenuIds(@RequestParam String dictValueId) {
+        return sysMenuDictRelationService.findMenuIdsByDictValueId(dictValueId);
+    }
+
+    /**
+     * 通知页面专用:根据当前用户权限返回可展示的字典値列表(Ajax)
+     */
+    @RequestMapping(value = "getDictValuesByPermission")
+    @ResponseBody
+    public List<Map<String, Object>> getDictValuesByPermission() {
+        return sysMenuDictRelationService.findDictValuesByCurrentUser();
+    }
+
+    /**
+     * 通知页面专用:根据当前用户权限返回可展示的通知字典値列表(Ajax)
+     */
+    @RequestMapping(value = "getNotifyDictValuesByPermission")
+    @ResponseBody
+    public List<Map<String, Object>> getNotifyDictValuesByPermission() {
+        return sysMenuDictRelationService.findNotifyDictValuesByCurrentUser();
+    }
+}
+

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

@@ -8,7 +8,7 @@ import java.util.List;
 
 /**
  * 知识库-动态字段配置表 DAO
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 @MyBatisDao

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

@@ -8,7 +8,7 @@ import java.util.List;
 
 /**
  * 知识库-动态字段値表 DAO
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 @MyBatisDao

+ 1 - 2
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/dao/WorkKnowledgeBaseShareInfoDao.java

@@ -3,14 +3,13 @@ package com.jeeplus.modules.WorkKnowledgeBase.dao;
 import com.jeeplus.common.persistence.CrudDao;
 import com.jeeplus.common.persistence.annotation.MyBatisDao;
 import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBaseShareInfo;
-import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 import java.util.Map;
 
 /**
  * 知识库-文件信息表 DAO
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 @MyBatisDao

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

@@ -8,7 +8,7 @@ import java.util.List;
 
 /**
  * 知识库-树形节点表 DAO
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 @MyBatisDao

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

@@ -4,7 +4,7 @@ import com.jeeplus.common.persistence.DataEntity;
 
 /**
  * 知识库-动态字段配置表实体
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 public class WorkKnowledgeBaseDynamicInfo extends DataEntity<WorkKnowledgeBaseDynamicInfo> {

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

@@ -4,7 +4,7 @@ import com.jeeplus.common.persistence.DataEntity;
 
 /**
  * 知识库-动态字段值表实体
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 public class WorkKnowledgeBaseDynamicValueInfo extends DataEntity<WorkKnowledgeBaseDynamicValueInfo> {

+ 38 - 7
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/entity/WorkKnowledgeBaseShareInfo.java

@@ -9,7 +9,7 @@ import java.util.Map;
 
 /**
  * 知识库-文件信息表实体(公共字段)
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 public class WorkKnowledgeBaseShareInfo extends DataEntity<WorkKnowledgeBaseShareInfo> {
@@ -17,6 +17,7 @@ public class WorkKnowledgeBaseShareInfo extends DataEntity<WorkKnowledgeBaseShar
     private String treeNodeId;    // 所属节点id
     private String fileName;      // 文件名
     private String fileUrl;       // 文件地址
+    private String name;       // 上传文件名称
     private Date createTime;      // 创建时间
 
     /** 所属根节点id(用于查询动态字段,非数据库字段) */
@@ -25,6 +26,12 @@ public class WorkKnowledgeBaseShareInfo extends DataEntity<WorkKnowledgeBaseShar
     /** 文件名模糊查询 */
     private String fileNameLike;
 
+    /** 创建时间区间查询(开始) */
+    private String beginDate;
+
+    /** 创建时间区间查询(结束) */
+    private String endDate;
+
     /** 动态字段值列表(保存时使用) */
     private List<WorkKnowledgeBaseDynamicValueInfo> dynamicValues;
 
@@ -34,8 +41,8 @@ public class WorkKnowledgeBaseShareInfo extends DataEntity<WorkKnowledgeBaseShar
     /** 动态字段查询条件(key=fieldId, value=queryValue) */
     private Map<String, String> dynamicConditions;
 
-    /** 附件列表(供 attachmentManager 回显用) */
-    private List<Workattachment> attachments;
+    /** 附件列表(与 ossupload.js 生成的 workAttachments[N].xxx 隐藏域绑定) */
+    private List<Workattachment> workAttachments;
 
     public String getTreeNodeId() {
         return treeNodeId;
@@ -61,6 +68,14 @@ public class WorkKnowledgeBaseShareInfo extends DataEntity<WorkKnowledgeBaseShar
         this.fileUrl = fileUrl;
     }
 
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
     public Date getCreateTime() {
         return createTime;
     }
@@ -85,6 +100,22 @@ public class WorkKnowledgeBaseShareInfo extends DataEntity<WorkKnowledgeBaseShar
         this.fileNameLike = fileNameLike;
     }
 
+    public String getBeginDate() {
+        return beginDate;
+    }
+
+    public void setBeginDate(String beginDate) {
+        this.beginDate = beginDate;
+    }
+
+    public String getEndDate() {
+        return endDate;
+    }
+
+    public void setEndDate(String endDate) {
+        this.endDate = endDate;
+    }
+
     public List<WorkKnowledgeBaseDynamicValueInfo> getDynamicValues() {
         return dynamicValues;
     }
@@ -109,11 +140,11 @@ public class WorkKnowledgeBaseShareInfo extends DataEntity<WorkKnowledgeBaseShar
         this.dynamicConditions = dynamicConditions;
     }
 
-    public List<Workattachment> getAttachments() {
-        return attachments;
+    public List<Workattachment> getWorkAttachments() {
+        return workAttachments;
     }
 
-    public void setAttachments(List<Workattachment> attachments) {
-        this.attachments = attachments;
+    public void setWorkAttachments(List<Workattachment> workAttachments) {
+        this.workAttachments = workAttachments;
     }
 }

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

@@ -6,7 +6,7 @@ import java.util.List;
 
 /**
  * 知识库-树形节点表实体
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 public class WorkKnowledgeBaseTreeInfo extends DataEntity<WorkKnowledgeBaseTreeInfo> {

+ 29 - 6
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseShareService.java

@@ -25,7 +25,7 @@ import java.util.Map;
 
 /**
  * 知识库-文件信息 Service
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 @Service
@@ -54,7 +54,10 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
         if (StringUtils.isBlank(fileId)) {
             return new ArrayList<>();
         }
-        return workattachmentService.getListByAttachmentIdAndFlag(fileId, ATTACHMENT_FLAG);
+        List<Workattachment> workattachmentList = workattachmentService.getListByAttachmentIdAndFlag(fileId, ATTACHMENT_FLAG);
+        //数据进行处理,添加临时预览url生成
+        workattachmentService.workAttachmentManage(workattachmentList);
+        return workattachmentList;
     }
 
     /**
@@ -101,7 +104,12 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
         page.setCountFlag(false);
 
         if (count > 0) {
-            page.setList(dao.findDynamicList(params));
+            List<Map<String, Object>> list = dao.findDynamicList(params);
+            for (Map<String, Object> map : list) {
+                map.put("uploadMode", entity.getUploadMode());
+            }
+            workattachmentService.attachmentManageByUrlOnWorkKnowledgeBaseShare(list);
+            page.setList(list);
         } else {
             page.setList(new ArrayList<>());
         }
@@ -123,7 +131,23 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
     @Transactional(readOnly = false)
     public void saveShare(WorkKnowledgeBaseShareInfo shareInfo) {
         boolean isNew = shareInfo.getIsNewRecord();
-        
+
+        // 从附件列表中提前提取第一个有效附件的 url,写入 file_url 字段
+        List<Workattachment> attachments = shareInfo.getWorkAttachments();
+        if (attachments != null) {
+            for (Workattachment attachment : attachments) {
+                if (attachment.getId() != null
+                        && Workattachment.DEL_FLAG_NORMAL.equals(attachment.getDelFlag())
+                        && StringUtils.isNotBlank(attachment.getUrl())) {
+                    String url = workattachmentService.disposeUrl(attachment);
+                    attachment.setUrl(url);
+                    shareInfo.setFileUrl(attachment.getUrl());
+                    shareInfo.setFileName(attachment.getAttachmentName() != null ? attachment.getAttachmentName() : "");
+                    break;
+                }
+            }
+        }
+
         if (isNew) {
             shareInfo.setId(IdGen.uuid());
             shareInfo.preInsert();
@@ -132,9 +156,8 @@ public class WorkKnowledgeBaseShareService extends CrudService<WorkKnowledgeBase
             shareInfo.preUpdate();
             dao.update(shareInfo);
         }
-        
+
         // 保存附件
-        List<Workattachment> attachments = shareInfo.getAttachments();
         if (attachments != null) {
             for (Workattachment attachment : attachments) {
                 if (attachment.getId() == null) {

+ 2 - 3
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/service/WorkKnowledgeBaseTreeService.java

@@ -16,7 +16,7 @@ import java.util.List;
 
 /**
  * 知识库-树形节点 Service
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 @Service
@@ -65,7 +65,7 @@ public class WorkKnowledgeBaseTreeService extends CrudService<WorkKnowledgeBaseT
         boolean isRoot = "0".equals(treeInfo.getParentId()) || StringUtils.isBlank(treeInfo.getParentId());
 
         if (isNew) {
-            treeInfo.setId(IdGen.uuid());
+            treeInfo.preInsert();
             if (isRoot) {
                 // 根节点:root_id = 自身id
                 treeInfo.setRootId(treeInfo.getId());
@@ -81,7 +81,6 @@ public class WorkKnowledgeBaseTreeService extends CrudService<WorkKnowledgeBaseT
                     treeInfo.setParentIds(parent.getParentIds() + parent.getId() + ",");
                 }
             }
-            treeInfo.preInsert();
             dao.insert(treeInfo);
         } else {
             treeInfo.preUpdate();

+ 48 - 3
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseShareController.java

@@ -25,7 +25,7 @@ import java.util.Map;
 
 /**
  * 知识库-文件信息管理 Controller
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 @Controller
@@ -97,6 +97,50 @@ public class WorkKnowledgeBaseShareController extends BaseController {
     }
 
     /**
+     * 详情页面(查看模式,不可编辑)
+     */
+    @RequiresPermissions(value = {"workKnowledgeBase:share:view", "workKnowledgeBase:share:edit"}, logical = org.apache.shiro.authz.annotation.Logical.OR)
+    @RequestMapping(value = "detail")
+    public String detail(WorkKnowledgeBaseShareInfo shareInfo, Model model) {
+        String rootId = shareInfo.getRootId();
+        String treeNodeId = shareInfo.getTreeNodeId();
+
+        if (StringUtils.isBlank(rootId) && StringUtils.isNotBlank(treeNodeId)) {
+            rootId = shareService.getRootIdByNodeId(treeNodeId);
+            shareInfo.setRootId(rootId);
+        }
+
+        // 查询动态字段配置
+        List<WorkKnowledgeBaseDynamicInfo> dynamicFields = new ArrayList<>();
+        if (StringUtils.isNotBlank(rootId)) {
+            dynamicFields = shareService.findDynamicFields(rootId);
+        }
+
+        // 加载动态字段已有值
+        Map<String, String> dynValues = new HashMap<>();
+        if (StringUtils.isNotBlank(shareInfo.getId())) {
+            List<WorkKnowledgeBaseDynamicValueInfo> existValues =
+                    shareService.findDynamicValuesByFileId(shareInfo.getId());
+            if (existValues != null) {
+                for (WorkKnowledgeBaseDynamicValueInfo val : existValues) {
+                    dynValues.put(val.getDynamicFieldId(), val.getFieldValue());
+                }
+            }
+        }
+
+        // 加载附件列表
+        if (StringUtils.isNotBlank(shareInfo.getId())) {
+            shareInfo.setWorkAttachments(shareService.findAttachmentsByFileId(shareInfo.getId()));
+        }
+
+        model.addAttribute("entity", shareInfo);
+        model.addAttribute("dynamicFields", dynamicFields);
+        model.addAttribute("rootId", rootId);
+        model.addAttribute("dynValues", dynValues);
+        return "modules/WorkKnowledgeBase/workKnowledgeBaseShareDetail";
+    }
+
+    /**
      * 新增/编辑表单页面
      * 编辑时将动态字段已有値加载到模型中(dynValues Map)
      */
@@ -132,7 +176,7 @@ public class WorkKnowledgeBaseShareController extends BaseController {
 
         // 编辑时加载已有附件列表(回显用)
         if (StringUtils.isNotBlank(shareInfo.getId())) {
-            shareInfo.setAttachments(shareService.findAttachmentsByFileId(shareInfo.getId()));
+            shareInfo.setWorkAttachments(shareService.findAttachmentsByFileId(shareInfo.getId()));
         }
 
         model.addAttribute("entity", shareInfo);
@@ -157,6 +201,7 @@ public class WorkKnowledgeBaseShareController extends BaseController {
         try {
             // 解析动态字段值
             if (StringUtils.isNotBlank(dynamicValuesJson)) {
+                dynamicValuesJson = dynamicValuesJson.replace("&quot;", "\"");
                 List<WorkKnowledgeBaseDynamicValueInfo> dynamicValues =
                         JSON.parseArray(dynamicValuesJson, WorkKnowledgeBaseDynamicValueInfo.class);
                 shareInfo.setDynamicValues(dynamicValues);
@@ -166,7 +211,7 @@ public class WorkKnowledgeBaseShareController extends BaseController {
         } catch (Exception e) {
             addMessage(redirectAttributes, "保存失败:" + e.getMessage());
         }
-        return "redirect:" + Global.getAdminPath() + "/workKnowledgeBase/share/list?treeNodeId=" + shareInfo.getTreeNodeId() + "&rootId=" + shareInfo.getRootId();
+        return "redirect:" + Global.getAdminPath() + "/workKnowledgeBase/share/list";
     }
 
     /**

+ 3 - 1
src/main/java/com/jeeplus/modules/WorkKnowledgeBase/web/WorkKnowledgeBaseTreeController.java

@@ -22,7 +22,7 @@ import java.util.Map;
 
 /**
  * 知识库-树形节点管理 Controller
- * @author: auto
+ * @author: 徐滕
  * @version: 2026-04-22
  */
 @Controller
@@ -114,6 +114,8 @@ public class WorkKnowledgeBaseTreeController extends BaseController {
         try {
             // 解析动态字段JSON
             if (StringUtils.isNotBlank(dynamicFieldsJson)) {
+                // 原来的字符串有 &quot;,先替换
+                dynamicFieldsJson = dynamicFieldsJson.replace("&quot;", "\"");
                 List<WorkKnowledgeBaseDynamicInfo> dynamicFields =
                         JSON.parseArray(dynamicFieldsJson, WorkKnowledgeBaseDynamicInfo.class);
                 treeInfo.setDynamicFields(dynamicFields);

+ 15 - 0
src/main/java/com/jeeplus/modules/WorkOssNoteInformInfo/dao/WorkOssNoteInformInfoDao.java

@@ -0,0 +1,15 @@
+package com.jeeplus.modules.WorkOssNoteInformInfo.dao;
+
+import com.jeeplus.common.persistence.CrudDao;
+import com.jeeplus.common.persistence.annotation.MyBatisDao;
+import com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo;
+
+/**
+ * 阿里云短信记录管理 DAO
+ * @author: 徐滕
+ * @version: 2026-04-22
+ */
+@MyBatisDao
+public interface WorkOssNoteInformInfoDao extends CrudDao<WorkOssNoteInformInfo> {
+
+}

+ 136 - 0
src/main/java/com/jeeplus/modules/WorkOssNoteInformInfo/entity/WorkOssNoteInformInfo.java

@@ -0,0 +1,136 @@
+package com.jeeplus.modules.WorkOssNoteInformInfo.entity;
+
+import com.jeeplus.common.persistence.DataEntity;
+
+import java.util.Date;
+
+/**
+ * 阿里云短信记录管理实体
+ * @author: 徐滕
+ * @version: 2026-04-22
+ */
+public class WorkOssNoteInformInfo extends DataEntity<WorkOssNoteInformInfo> {
+
+    /** 接收人ID */
+    private String receiveUserId;
+
+    /** 接收人名称 */
+    private String receiveUserName;
+
+    /** 短信发送时间 */
+    private Date sendTime;
+
+    /** 短信接收手机号 */
+    private String phone;
+
+    /** 短信正文内容 */
+    private String sendContent;
+
+    /** 短信类型(自定义业务分类) */
+    private String smsType;
+
+    /** 短信所属业务模块 */
+    private String smsModule;
+
+    /** 发送结果状态 */
+    private String statusCode;
+
+    /** 发送结果 */
+    private String message;
+
+    // ---------- 查询条件(非DB字段) ----------
+
+    /** 发送时间区间-开始 */
+    private Date sendTimeStart;
+
+    /** 发送时间区间-结束 */
+    private Date sendTimeEnd;
+
+    public String getReceiveUserId() {
+        return receiveUserId;
+    }
+
+    public void setReceiveUserId(String receiveUserId) {
+        this.receiveUserId = receiveUserId;
+    }
+
+    public String getReceiveUserName() {
+        return receiveUserName;
+    }
+
+    public void setReceiveUserName(String receiveUserName) {
+        this.receiveUserName = receiveUserName;
+    }
+
+    public Date getSendTime() {
+        return sendTime;
+    }
+
+    public void setSendTime(Date sendTime) {
+        this.sendTime = sendTime;
+    }
+
+    public String getSendContent() {
+        return sendContent;
+    }
+
+    public void setSendContent(String sendContent) {
+        this.sendContent = sendContent;
+    }
+
+    public String getSmsType() {
+        return smsType;
+    }
+
+    public void setSmsType(String smsType) {
+        this.smsType = smsType;
+    }
+
+    public String getSmsModule() {
+        return smsModule;
+    }
+
+    public void setSmsModule(String smsModule) {
+        this.smsModule = smsModule;
+    }
+
+    public Date getSendTimeStart() {
+        return sendTimeStart;
+    }
+
+    public void setSendTimeStart(Date sendTimeStart) {
+        this.sendTimeStart = sendTimeStart;
+    }
+
+    public Date getSendTimeEnd() {
+        return sendTimeEnd;
+    }
+
+    public void setSendTimeEnd(Date sendTimeEnd) {
+        this.sendTimeEnd = sendTimeEnd;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    public String getStatusCode() {
+        return statusCode;
+    }
+
+    public void setStatusCode(String statusCode) {
+        this.statusCode = statusCode;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}

+ 41 - 0
src/main/java/com/jeeplus/modules/WorkOssNoteInformInfo/service/WorkOssNoteInformInfoService.java

@@ -0,0 +1,41 @@
+package com.jeeplus.modules.WorkOssNoteInformInfo.service;
+
+import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.service.CrudService;
+import com.jeeplus.modules.WorkOssNoteInformInfo.dao.WorkOssNoteInformInfoDao;
+import com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 阿里云短信记录管理 Service
+ * @author: 徐滕
+ * @version: 2026-04-22
+ */
+@Service
+@Transactional(readOnly = true)
+public class WorkOssNoteInformInfoService extends CrudService<WorkOssNoteInformInfoDao, WorkOssNoteInformInfo> {
+
+    /**
+     * 分页查询短信记录列表
+     *
+     * @param page   分页参数
+     * @param entity 查询条件实体
+     * @return 分页结果
+     */
+    public Page<WorkOssNoteInformInfo> findPage(Page<WorkOssNoteInformInfo> page, WorkOssNoteInformInfo entity) {
+        return super.findPage(page, entity);
+    }
+
+    /**
+     * 保存短信记录(供其他业务模块内部调用)
+     * 仅做新增,无业务校验
+     *
+     * @param entity 短信记录实体
+     */
+    @Transactional(readOnly = false)
+    public void saveRecord(WorkOssNoteInformInfo entity) {
+        entity.preInsert();
+        dao.insert(entity);
+    }
+}

+ 77 - 0
src/main/java/com/jeeplus/modules/WorkOssNoteInformInfo/web/WorkOssNoteInformInfoController.java

@@ -0,0 +1,77 @@
+package com.jeeplus.modules.WorkOssNoteInformInfo.web;
+
+import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.common.web.BaseController;
+import com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo;
+import com.jeeplus.modules.WorkOssNoteInformInfo.service.WorkOssNoteInformInfoService;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 阿里云短信记录管理 Controller
+ * @author: 徐滕
+ * @version: 2026-04-22
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/workOssNoteInformInfo")
+public class WorkOssNoteInformInfoController extends BaseController {
+
+    @Autowired
+    private WorkOssNoteInformInfoService workOssNoteInformInfoService;
+
+    @ModelAttribute
+    public WorkOssNoteInformInfo get(@RequestParam(required = false) String id) {
+        WorkOssNoteInformInfo entity = null;
+        if (StringUtils.isNotBlank(id)) {
+            entity = workOssNoteInformInfoService.get(id);
+        }
+        if (entity == null) {
+            entity = new WorkOssNoteInformInfo();
+        }
+        return entity;
+    }
+
+    /**
+     * 列表页面(分页查询)
+     */
+    @RequiresPermissions("workOssNoteInformInfo:list")
+    @RequestMapping(value = {"list", ""})
+    public String list(WorkOssNoteInformInfo entity,
+                       HttpServletRequest request, HttpServletResponse response, Model model) {
+        Page<WorkOssNoteInformInfo> page = new Page<>(request, response);
+        page = workOssNoteInformInfoService.findPage(page, entity);
+        model.addAttribute("page", page);
+        model.addAttribute("entity", entity);
+        return "modules/WorkOssNoteInformInfo/workOssNoteInformInfoList";
+    }
+
+    /**
+     * 保存短信记录(供其他业务模块内部调用,POST方式,仅新增)
+     *
+     * @param entity 短信记录实体
+     * @return 操作结果 Map
+     */
+    @RequestMapping(value = "save", method = RequestMethod.POST)
+    @ResponseBody
+    public Map<String, Object> save(@RequestBody WorkOssNoteInformInfo entity) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            workOssNoteInformInfoService.saveRecord(entity);
+            result.put("success", true);
+            result.put("message", "保存成功");
+        } catch (Exception e) {
+            result.put("success", false);
+            result.put("message", "保存失败:" + e.getMessage());
+        }
+        return result;
+    }
+}

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

@@ -743,6 +743,24 @@ public class RuralProjectRecordsController extends BaseController {
 	}
 
 	/**
+	 * 删除项目
+	 */
+	@RequestMapping(value = "adminDeleteOnPost")
+	public String adminDeleteOnPost(RuralProjectRecords projectRecords, RedirectAttributes redirectAttributes) {
+		int status = projectRecords.getProjectStatus();
+		Map map = new HashMap();
+		if(status== ProjectStatusEnum.SIGNED.getValue()){
+			projectRecordsService.adminDelete(projectRecords);
+			addMessage(redirectAttributes, "管理员删除项目成功");
+			return "redirect:"+Global.getAdminPath()+"/ruralProject/ruralProjectRecords/?repage";
+		}else {
+			addMessage(redirectAttributes, "管理员删除项目失败");
+			map.put("failure","删除失败");
+		}
+		return "redirect:"+Global.getAdminPath()+"/ruralProject/ruralProjectRecords/?repage";
+	}
+
+	/**
 	 * 批量删除项目
 	 */
 	@RequiresPermissions("ruralProject:ruralProjectRecords:del")

+ 7 - 0
src/main/java/com/jeeplus/modules/ruralprojectrecords/web/RuralProjectSignatureOldMessageDisposeController.java

@@ -1224,6 +1224,13 @@ public class RuralProjectSignatureOldMessageDisposeController extends BaseContro
         //查询一级造价师的信息
         List<WorkStaffCertificate> firstCostEngineerList = workStaffCertificateService.getFirstCostEngineerList();
         for (WorkStaffCertificate workStaffCertificate : firstCostEngineerList) {
+            //查询是否进行了提交申请,如果提交了申请,也不进行通知
+            Integer submitApplicationsById = workStaffCertificateService.getSubmitApplicationsById(workStaffCertificate.getId());
+            if(submitApplicationsById>0){
+                continue;
+            }
+
+
             if(null != workStaffCertificate.getValidEndDate()){
                 //如果有使用有效期,则让其进行和当前时间进行判定,提前7天进行提醒
                 // 获取结束时间(数据库取出来的 Date)

+ 6 - 7
src/main/java/com/jeeplus/modules/sys/dao/UserDao.java

@@ -3,17 +3,15 @@
  */
 package com.jeeplus.modules.sys.dao;
 
-import java.util.HashMap;
-import java.util.List;
-
-import com.jeeplus.modules.sys.entity.Office;
-import com.jeeplus.modules.workstaff.entity.WorkStaffBasicInfo;
-import org.apache.ibatis.annotations.Param;
-
 import com.jeeplus.common.persistence.CrudDao;
 import com.jeeplus.common.persistence.annotation.MyBatisDao;
+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.workstaff.entity.WorkStaffBasicInfo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * 用户DAO接口
@@ -31,6 +29,7 @@ public interface UserDao extends CrudDao<User> {
 	public User getByLoginName(User user);
 	public List<User> getByName(User user);
 	public List<User> getUserByName(@Param("name")String name);
+	public User getUserByMobile(@Param("mobile")String mobile);
 
 	public User getByUserId(String id);
 	public User findUserByNo(@Param("no")String no,@Param("companyId")String companyId);

+ 41 - 5
src/main/java/com/jeeplus/modules/sys/service/WorkattachmentService.java

@@ -10,7 +10,6 @@ import com.jeeplus.common.persistence.Page;
 import com.jeeplus.common.service.CrudService;
 import com.jeeplus.common.utils.StringUtils;
 import com.jeeplus.modules.externalUnit.entity.ExternalUnitWorkClientAttachment;
-import com.jeeplus.modules.isignature.service.ISignatureDocumentService;
 import com.jeeplus.modules.projectAccessory.dao.ProjectAccessoryDao;
 import com.jeeplus.modules.projectAccessory.entity.CollectAccessoryInfo;
 import com.jeeplus.modules.projectAccessory.utils.ProjectAccessoryUtil;
@@ -21,16 +20,12 @@ import com.jeeplus.modules.sys.utils.UserUtils;
 import com.jeeplus.modules.utils.ViewFileUtil;
 import com.jeeplus.modules.workclientinfo.dao.WorkClientAttachmentDao;
 import com.jeeplus.modules.workclientinfo.entity.WorkClientAttachment;
-import org.apache.commons.io.FilenameUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartHttpServletRequest;
-import sun.awt.AWTCharset;
-import sun.nio.cs.SingleByte;
 
-import java.math.BigDecimal;
 import java.net.URLDecoder;
 import java.util.*;
 
@@ -404,6 +399,27 @@ public class WorkattachmentService extends CrudService<WorkattachmentDao, Workat
 		workClientAttachmentDao.insert(workattachment);
 	}
 
+
+	/**
+	 * 附件地址的处理
+	 * @param workattachment
+	 */
+	@Transactional(readOnly = false)
+	public String disposeUrl(Workattachment workattachment) {
+		//字符处理
+		workattachment.setUrl(decodeHtmlEntities(workattachment.getUrl()));
+		switch (uploadMode){
+			case "1":
+				workattachment.setUrl(workattachment.getUrl().replace(bosUrl,""));
+				break;
+			case "2":
+				workattachment.setUrl(workattachment.getUrl().replace(aliyunUrl,""));
+				break;
+		}
+
+		return workattachment.getUrl();
+	}
+
 	/**
 	 * 新增附件(外部单位)
 	 * @param workattachment
@@ -906,6 +922,7 @@ public class WorkattachmentService extends CrudService<WorkattachmentDao, Workat
 					break;
 				case "2":
 					info.setUrl(aliyunUrl + info.getUrl());
+					info.setTemporaryUrl(new OSSClientUtil().getFileTemporaryLookUrl(info.getUrl()));
 					break;
 				default:
 					//获取本地服务器ip和端口号
@@ -1241,6 +1258,25 @@ public class WorkattachmentService extends CrudService<WorkattachmentDao, Workat
 			}
 		}
 	}
+	/**
+	 * 此方法仅用于知识库灵活表头处
+	 * @param list
+	 */
+	public static void attachmentManageByUrlOnWorkKnowledgeBaseShare(List<Map<String, Object>> list){
+		// 判断文件存储方式(0:本地服务器存储。1:云端存储)
+		for (Map<String, Object> info : list) {
+			switch (uploadMode){
+				case "1":
+					info.put("fileUrl", bosUrl + info.get("fileUrl"));
+					break;
+				case "2":
+					info.put("fileUrl", aliyunUrl + info.get("fileUrl"));
+					info.put("temporaryUrl", new OSSClientUtil().getFileTemporaryLookUrl((String) info.get("fileUrl")));
+					break;
+
+			}
+		}
+	}
 
 
 	/**

+ 213 - 2
src/main/java/com/jeeplus/modules/sys/utils/ALiYunSmsUtil.java

@@ -1,11 +1,13 @@
 package com.jeeplus.modules.sys.utils;
 
 import com.aliyun.dysmsapi20170525.Client;
-import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
-import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
+import com.aliyun.dysmsapi20170525.models.*;
 import com.aliyun.teaopenapi.models.Config;
 
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * @author: 徐滕
@@ -58,12 +60,26 @@ public class ALiYunSmsUtil {
                 map.put("statusCode",10001);
             }else if(sendSmsResponse.body.code.contains("isv.AMOUNT_NOT_ENOUGH")){
                 //触发账户余额不足
+                map.put("message","阿里云账户月不足!");
                 map.put("statusCode",10002);
             }else if(sendSmsResponse.body.code.contains("isv.DAY_LIMIT_CONTROL")){
                 //触发触发日发送限额
+                map.put("message","短信当日发送限额!");
                 map.put("statusCode",10003);
             }else if(sendSmsResponse.body.code.contains("OK")){
                 map.put("statusCode",sendSmsResponse.getStatusCode());
+                map.put("message", "短信发送成功");
+
+                // 必须等待 2 秒,不打断点也能拿到内容
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+
+                // ========== 核心:调用阿里云接口 查询【真实完整短信内容】 ==========
+                String smsContent = querySmsContent(client, phoneNumbers, sendSmsResponse.body.bizId);
+                map.put("smsContent", smsContent); // 这里就是用户收到的完整短信!
             }
             return map;
         } catch (Exception error) {
@@ -108,12 +124,26 @@ public class ALiYunSmsUtil {
                 map.put("statusCode",10001);
             }else if(sendSmsResponse.body.code.contains("isv.AMOUNT_NOT_ENOUGH")){
                 //触发账户余额不足
+                map.put("message","阿里云账户月不足!");
                 map.put("statusCode",10002);
             }else if(sendSmsResponse.body.code.contains("isv.DAY_LIMIT_CONTROL")){
                 //触发触发日发送限额
+                map.put("message","短信当日发送限额!");
                 map.put("statusCode",10003);
             }else if(sendSmsResponse.body.code.contains("OK")){
                 map.put("statusCode",sendSmsResponse.getStatusCode());
+                map.put("message", "短信发送成功");
+
+                // 必须等待 2 秒,不打断点也能拿到内容
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+
+                // ========== 核心:调用阿里云接口 查询【真实完整短信内容】 ==========
+                String smsContent = querySmsContent(client, phoneNumbers, sendSmsResponse.body.bizId);
+                map.put("smsContent", smsContent); // 这里就是用户收到的完整短信!
             }
             return map;
         } catch (Exception error) {
@@ -160,12 +190,26 @@ public class ALiYunSmsUtil {
                 map.put("statusCode",10001);
             }else if(sendSmsResponse.body.code.contains("isv.AMOUNT_NOT_ENOUGH")){
                 //触发账户余额不足
+                map.put("message","阿里云账户月不足!");
                 map.put("statusCode",10002);
             }else if(sendSmsResponse.body.code.contains("isv.DAY_LIMIT_CONTROL")){
                 //触发触发日发送限额
+                map.put("message","短信当日发送限额!");
                 map.put("statusCode",10003);
             }else if(sendSmsResponse.body.code.contains("OK")){
                 map.put("statusCode",sendSmsResponse.getStatusCode());
+                map.put("message", "短信发送成功");
+
+                // 必须等待 2 秒,不打断点也能拿到内容
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+
+                // ========== 核心:调用阿里云接口 查询【真实完整短信内容】 ==========
+                String smsContent = querySmsContent(client, phoneNumbers, sendSmsResponse.body.bizId);
+                map.put("smsContent", smsContent); // 这里就是用户收到的完整短信!
             }
             return map;
         } catch (Throwable error) {  // 捕获所有异常和错误
@@ -215,12 +259,26 @@ public class ALiYunSmsUtil {
                 map.put("statusCode",10001);
             }else if(sendSmsResponse.body.code.contains("isv.AMOUNT_NOT_ENOUGH")){
                 //触发账户余额不足
+                map.put("message","阿里云账户月不足!");
                 map.put("statusCode",10002);
             }else if(sendSmsResponse.body.code.contains("isv.DAY_LIMIT_CONTROL")){
                 //触发触发日发送限额
+                map.put("message","短信当日发送限额!");
                 map.put("statusCode",10003);
             }else if(sendSmsResponse.body.code.contains("OK")){
                 map.put("statusCode",sendSmsResponse.getStatusCode());
+                map.put("message", "短信发送成功");
+
+                // 必须等待 2 秒,不打断点也能拿到内容
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+
+                // ========== 核心:调用阿里云接口 查询【真实完整短信内容】 ==========
+                String smsContent = querySmsContent(client, phoneNumbers, sendSmsResponse.body.bizId);
+                map.put("smsContent", smsContent); // 这里就是用户收到的完整短信!
             }
             return map;
         } catch (Throwable error) {  // 捕获所有异常和错误
@@ -230,4 +288,157 @@ public class ALiYunSmsUtil {
         }
     }
 
+    /**
+     * oms开票成功通知短信
+     * @param phoneNumbers  被通知手机号
+     * @param number    被通知的参数(此处为开票编号)
+     * @return
+     * @throws Exception
+     */
+    public static HashMap<String,Object> updateUncollectedInformSms(String name, String phoneNumbers, String number) {
+        HashMap<String,Object> map = new HashMap<>();
+        try {
+            Config config = new Config()
+                    .setAccessKeyId(ACCESS_KEY_ID)
+                    .setAccessKeySecret(ACCESS_KEY_SECRET)
+                    .setEndpoint(ENDPOINT);
+
+            Client client = new Client(config);
+            // 构造参数
+            String templateParams = String.format("{\"name\":\"%s\",\"invoiceNumber\":\"%s\"}", name, number);
+            String templateCode = "SMS_505775137"; // 模板CODE
+            String signName = SIGNNAME;            // 签名
+
+            SendSmsRequest sendSmsRequest = new SendSmsRequest()
+                    .setPhoneNumbers(phoneNumbers)
+                    .setSignName(signName)
+                    .setTemplateCode(templateCode)
+                    .setTemplateParam(templateParams);
+
+            // 发送短信
+            SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
+
+            // ====================== 关键:把短信所有信息存入 map ======================
+            map.put("phoneNumbers", phoneNumbers);        // 接收手机号
+            map.put("signName", signName);                // 短信签名
+            map.put("templateCode", templateCode);        // 短信模板ID
+            map.put("templateParams", templateParams);    // 短信参数(name、发票号)
+            map.put("requestId", sendSmsResponse.body.requestId); // 请求ID
+            map.put("bizId", sendSmsResponse.body.bizId); // 发送回执ID(可查具体发送状态)
+            map.put("code", sendSmsResponse.body.code);   // 返回码
+            map.put("message", sendSmsResponse.body.message); // 返回描述
+
+            // 原来的错误判断逻辑保留
+            if("isv.BUSINESS_LIMIT_CONTROL".equals(sendSmsResponse.body.code)){
+                String msg = sendSmsResponse.body.message;
+                if(msg.contains("分钟级")){
+                    map.put("message", "手机号获取验证码次数已触发每分钟可发送数量上限,请稍后重试!");
+                }else if(msg.contains("小时级")){
+                    map.put("message", "手机号获取验证码次数已触发每小时可发送数量上限,请稍后重试!");
+                }else{
+                    map.put("message", "手机号获取验证码次数已触发每日可发送数量上限,请稍后重试!");
+                }
+                map.put("statusCode", 10001);
+            }else if(sendSmsResponse.body.code.contains("isv.AMOUNT_NOT_ENOUGH")){
+                //触发账户余额不足
+                map.put("message","阿里云账户月不足!");
+                map.put("statusCode",10002);
+            }else if(sendSmsResponse.body.code.contains("isv.DAY_LIMIT_CONTROL")){
+                //触发触发日发送限额
+                map.put("message","短信当日发送限额!");
+                map.put("statusCode",10003);
+            }else if("OK".equals(sendSmsResponse.body.code)){
+                map.put("statusCode", 200);
+                map.put("message", "短信发送成功");
+
+                // 必须等待 2 秒,不打断点也能拿到内容
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+
+                // ========== 核心:调用阿里云接口 查询【真实完整短信内容】 ==========
+                String smsContent = querySmsContent(client, phoneNumbers, sendSmsResponse.body.bizId);
+                map.put("smsContent", smsContent); // 这里就是用户收到的完整短信!
+
+            }else{
+                map.put("statusCode", 400);
+            }
+
+            return map;
+
+        } catch (Throwable error) {
+            map.put("statusCode", 500);
+            map.put("message", "发送失败:" + error.getMessage());
+            // 异常时也记录基础信息
+            map.put("phoneNumbers", phoneNumbers);
+            map.put("templateParams", String.format("{name:%s, invoiceNumber:%s}", name, number));
+            return map;
+        }
+    }
+
+
+    /**
+     * 查询短信发送后的实际内容(含签名+模版变量替换后的完整用户收到的内容)
+     * <p>
+     * 注意:阵云短信发送后通常有延迟,建议延迟 1~2 秒再查询。
+     * 返回内容示例:【江苏兴光会计师事务所】您的验证码是 1234,请勿泄露。
+     * 如未查询到,返回空字符串。
+     * </p>
+     *
+     * @param client       已初始化的阵云短信 Client
+     * @param phoneNumbers 接收手机号(单个)
+     * @param bizId        发送短信返回的回执 ID(sendSmsResponse.body.bizId)
+     * @return 用户实际收到的短信内容,如果未查询到则返回空字符串
+     */
+    public static String querySmsContent(Client client, String phoneNumbers, String bizId) {
+        int retryCount = 5; // 最多重试3次
+        long sleepTime = 1000; // 每次间隔800ms
+
+        while (retryCount-- > 0) {
+            try {
+                String sendDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
+                QuerySendDetailsRequest querySendDetailsRequest = new QuerySendDetailsRequest()
+                        .setPhoneNumber(phoneNumbers)
+                        .setBizId(bizId)
+                        .setSendDate(sendDate)
+                        .setPageSize(1L)
+                        .setCurrentPage(1L);
+
+                QuerySendDetailsResponse queryResp = client.querySendDetails(querySendDetailsRequest);
+
+                if (queryResp == null || queryResp.body == null
+                        || queryResp.body.smsSendDetailDTOs == null
+                        || queryResp.body.smsSendDetailDTOs.smsSendDetailDTO == null) {
+                    Thread.sleep(sleepTime);
+                    continue;
+                }
+
+                // 这里改成 Java 8 标准写法
+                List<QuerySendDetailsResponseBody.QuerySendDetailsResponseBodySmsSendDetailDTOsSmsSendDetailDTO> details =
+                        queryResp.body.smsSendDetailDTOs.smsSendDetailDTO;
+
+                if (details.isEmpty()) {
+                    Thread.sleep(sleepTime);
+                    continue;
+                }
+
+                String content = details.get(0).content;
+                if (content != null && !content.trim().isEmpty()) {
+                    return content;
+                }
+
+                Thread.sleep(sleepTime);
+            } catch (Exception e) {
+                try {
+                    Thread.sleep(sleepTime);
+                } catch (Exception ignored) {
+                }
+            }
+        }
+
+        return "";
+    }
+
 }

+ 10 - 4
src/main/java/com/jeeplus/modules/sys/utils/UserUtils.java

@@ -5,11 +5,9 @@ package com.jeeplus.modules.sys.utils;
 
 import com.jeeplus.common.config.Global;
 import com.jeeplus.common.oss.OSSClientUtil;
-import com.jeeplus.common.persistence.Page;
 import com.jeeplus.common.service.BaseService;
 import com.jeeplus.common.sms.SMSUtils;
 import com.jeeplus.common.utils.*;
-import com.jeeplus.common.websocket.onchat.ChatServerPool;
 import com.jeeplus.modules.activityassignment.dao.ActivityAssignmentDao;
 import com.jeeplus.modules.activityassignment.entity.ActivityAssignment;
 import com.jeeplus.modules.sys.dao.*;
@@ -30,11 +28,9 @@ import com.jeeplus.modules.workstaff.dao.WorkStaffBasicInfoDao;
 import com.jeeplus.modules.workstaff.entity.WorkStaffBasicInfo;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.UnavailableSecurityManagerException;
-import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.session.InvalidSessionException;
 import org.apache.shiro.session.Session;
 import org.apache.shiro.subject.Subject;
-import org.java_websocket.WebSocket;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.IOException;
@@ -228,6 +224,16 @@ public class UserUtils {
 		List<User> list = userDao.getUserByName(name);
 		return list;
 	}
+	/**
+	 * 根据登录名获取用户
+	 * @param name
+	 * @return 取不到返回null
+	 */
+	public static User getUserByMobile(String mobile){
+
+		User list = userDao.getUserByMobile(mobile);
+		return list;
+	}
 
 	/**
 	 * 根据登录名获取用户

+ 26 - 11
src/main/java/com/jeeplus/modules/sys/web/LoginController.java

@@ -3,11 +3,8 @@
  */
 package com.jeeplus.modules.sys.web;
 
-import cn.hutool.captcha.CaptchaUtil;
-import cn.hutool.captcha.LineCaptcha;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
-import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.jeeplus.common.config.Global;
 import com.jeeplus.common.json.AjaxJson;
@@ -16,11 +13,10 @@ import com.jeeplus.common.security.shiro.session.SessionDAO;
 import com.jeeplus.common.servlet.ValidateCodeServlet;
 import com.jeeplus.common.utils.*;
 import com.jeeplus.common.web.BaseController;
-import com.jeeplus.common.websocket.onchat.ChatServerPool;
+import com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo;
+import com.jeeplus.modules.WorkOssNoteInformInfo.service.WorkOssNoteInformInfoService;
 import com.jeeplus.modules.centerservice.service.cpa.task.TaskFlowService;
 import com.jeeplus.modules.centerservice.utils.ConvertServiceUtil;
-import com.jeeplus.modules.iim.entity.MailBox;
-import com.jeeplus.modules.iim.entity.MailPage;
 import com.jeeplus.modules.iim.service.MailBoxService;
 import com.jeeplus.modules.knowledgeSharing.entity.KnowledgeSharingInfo;
 import com.jeeplus.modules.knowledgeSharing.entity.KnowledgeSharingTypeInfo;
@@ -35,7 +31,6 @@ import com.jeeplus.modules.ruralprojectrecords.service.RuralProjectRecordsServic
 import com.jeeplus.modules.sys.dao.UserDao;
 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.security.FormAuthenticationFilter;
 import com.jeeplus.modules.sys.security.SystemAuthorizingRealm.Principal;
@@ -51,11 +46,9 @@ import com.jeeplus.modules.szCenterservice.service.szCloud.SzFlowRequest;
 import com.jeeplus.modules.szCenterservice.utils.SzConvertServiceUtil;
 import com.jeeplus.modules.utils.ErrorCode;
 import com.jeeplus.modules.workbidproject.service.WorkBidProjectService;
-import com.jeeplus.modules.workcalendar.entity.WorkCalendar;
 import com.jeeplus.modules.workcalendar.service.WorkCalendarService;
 import com.jeeplus.modules.workprojectnotify.entity.WorkProjectNotify;
 import com.jeeplus.modules.workprojectnotify.service.WorkProjectNotifyService;
-import net.sf.json.JSONArray;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authz.UnauthorizedException;
@@ -63,7 +56,6 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.apache.shiro.web.util.SavedRequest;
 import org.apache.shiro.web.util.WebUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -77,7 +69,6 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 import java.io.IOException;
-import java.text.SimpleDateFormat;
 import java.time.Duration;
 import java.time.LocalDateTime;
 import java.util.*;
@@ -125,6 +116,8 @@ public class LoginController extends BaseController{
 
 	@Autowired
 	private SzFlowRequest szFlowRequest;
+	@Autowired
+	private WorkOssNoteInformInfoService workOssNoteInformInfoService;
 
 	/**
 	 * 管理登录
@@ -867,6 +860,28 @@ public class LoginController extends BaseController{
 					j.put("ErrorXml",result);
 				}
 
+				User user = UserUtils.getUserByMobile(mobile);
+				//获取短信发送内容
+				String smsContent = (String) result.get("smsContent");
+				//获取短信发送结果
+				String message = (String) result.get("message");
+				//将短信发送信息保存到数据库中
+				WorkOssNoteInformInfo workOssNoteInformInfo = new WorkOssNoteInformInfo();
+				workOssNoteInformInfo.setReceiveUserId(user.getId());
+				workOssNoteInformInfo.setSendTime(new Date());
+				workOssNoteInformInfo.setSendContent(smsContent);
+				workOssNoteInformInfo.setPhone(user.getMobile()==null?"":user.getMobile());
+
+				if(200 == statusCode){
+					workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+					workOssNoteInformInfo.setMessage(message);
+					workOssNoteInformInfo.setSmsModule("快速登陆");
+				}else{
+					workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+					workOssNoteInformInfo.setMessage(message);
+				}
+				workOssNoteInformInfoService.saveRecord(workOssNoteInformInfo);
+
 			}catch (Exception e){
 				e.printStackTrace();
 				logger.info("5");

+ 36 - 7
src/main/java/com/jeeplus/modules/sys/web/RegisterController.java

@@ -1,25 +1,24 @@
 package com.jeeplus.modules.sys.web;
 
 
-import com.easemob.server.example.api.impl.EasemobIMUsers;
-import com.jeeplus.common.config.Global;
 import com.jeeplus.common.json.AjaxJson;
 import com.jeeplus.common.utils.EncrypeUtil;
 import com.jeeplus.common.utils.JedisUtils;
 import com.jeeplus.common.utils.StringUtils;
 import com.jeeplus.common.web.BaseController;
+import com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo;
+import com.jeeplus.modules.WorkOssNoteInformInfo.service.WorkOssNoteInformInfoService;
 import com.jeeplus.modules.sys.dao.UserDao;
-import com.jeeplus.modules.sys.entity.*;
-import com.jeeplus.modules.sys.security.FormAuthenticationFilter;
+import com.jeeplus.modules.sys.entity.MainDictDetail;
+import com.jeeplus.modules.sys.entity.User;
 import com.jeeplus.modules.sys.service.OfficeService;
 import com.jeeplus.modules.sys.service.SystemConfigService;
 import com.jeeplus.modules.sys.service.SystemService;
+import com.jeeplus.modules.sys.utils.ALiYunSmsUtil;
 import com.jeeplus.modules.sys.utils.DictUtils;
 import com.jeeplus.modules.sys.utils.UserUtils;
 import com.jeeplus.modules.utils.ErrorCode;
-import net.sf.json.JSONObject;
 import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.ibatis.annotations.Param;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -29,10 +28,10 @@ import redis.clients.jedis.Jedis;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import com.jeeplus.modules.sys.utils.ALiYunSmsUtil;
 
 /**
  * 用户Controller
@@ -55,6 +54,8 @@ public class RegisterController extends BaseController {
 
 	@Autowired
 	private UserDao userDao;
+	@Autowired
+	private WorkOssNoteInformInfoService workOssNoteInformInfoService;
 
 	@ModelAttribute
 	public User get(@RequestParam(required=false) String id) {
@@ -349,6 +350,34 @@ public class RegisterController extends BaseController {
 				j.put("message","短信发送失败,错误代码:101,请联系管理员!");
 				j.put("ErrorXml",result);
 			}
+
+
+
+			User user = UserUtils.getUserByMobile(mobile);
+			//获取短信发送内容
+			String smsContent = (String) result.get("smsContent");
+			//获取短信发送结果
+			String message = (String) result.get("message");
+			//将短信发送信息保存到数据库中
+			WorkOssNoteInformInfo workOssNoteInformInfo = new WorkOssNoteInformInfo();
+			workOssNoteInformInfo.setReceiveUserId(user.getId());
+			workOssNoteInformInfo.setSendTime(new Date());
+			workOssNoteInformInfo.setSendContent(smsContent);
+			workOssNoteInformInfo.setPhone(user.getMobile()==null?"":user.getMobile());
+
+			if(200 == statusCode){
+				workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+				workOssNoteInformInfo.setMessage(message);
+				workOssNoteInformInfo.setSmsModule("密码修改");
+			}else{
+				workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+				workOssNoteInformInfo.setMessage(message);
+			}
+			workOssNoteInformInfoService.saveRecord(workOssNoteInformInfo);
+
+
+
+
 		}catch (Exception e){
 			System.out.println("阿里云发送短信失败。失败原因为:" + e.getMessage());
 			logger.error("调用短信接口发生错误", e);  // 记录详细日志

+ 9 - 19
src/main/java/com/jeeplus/modules/syswarning/service/SysWarningService.java

@@ -3,14 +3,8 @@
  */
 package com.jeeplus.modules.syswarning.service;
 
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.*;
-
-import com.jeeplus.common.config.Global;
-import com.jeeplus.common.sms.SMSUtils;
-import com.jeeplus.common.utils.JedisUtils;
+import com.jeeplus.common.persistence.Page;
+import com.jeeplus.common.service.CrudService;
 import com.jeeplus.common.utils.SendMailUtil;
 import com.jeeplus.common.utils.StringUtils;
 import com.jeeplus.modules.sys.dao.UserDao;
@@ -20,32 +14,29 @@ import com.jeeplus.modules.sys.utils.DictUtils;
 import com.jeeplus.modules.sys.utils.UserUtils;
 import com.jeeplus.modules.sysmodular.dao.SysModularDao;
 import com.jeeplus.modules.sysmodular.dao.SysModularFieldDao;
-import com.jeeplus.modules.sysmodular.entity.SysModular;
 import com.jeeplus.modules.sysmodular.entity.SysModularField;
+import com.jeeplus.modules.syswarning.dao.SysWarningDao;
 import com.jeeplus.modules.syswarning.dao.SysWarningLogDao;
 import com.jeeplus.modules.syswarning.dao.SysWarningRoleDao;
 import com.jeeplus.modules.syswarning.dao.SysWarningUserDao;
+import com.jeeplus.modules.syswarning.entity.SysWarning;
 import com.jeeplus.modules.syswarning.entity.SysWarningLog;
 import com.jeeplus.modules.syswarning.entity.SysWarningRole;
 import com.jeeplus.modules.syswarning.entity.SysWarningUser;
-import com.jeeplus.modules.workcatalogueitem.entity.WorkCatalogueItem;
-import com.jeeplus.modules.workchangejob.entity.WorkChangeJob;
-import com.jeeplus.modules.workchangejob.entity.WorkChangeJobUser;
 import com.jeeplus.modules.workprojectnotify.entity.WorkProjectNotify;
 import com.jeeplus.modules.workprojectnotify.service.WorkProjectNotifyService;
 import com.jeeplus.modules.workprojectnotify.util.UtilNotify;
 import com.jeeplus.modules.workstaff.dao.WorkStaffAchivesDao;
 import com.jeeplus.modules.workstaff.entity.WorkStaffBasicInfo;
-import net.sf.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import com.jeeplus.common.persistence.Page;
-import com.jeeplus.common.service.CrudService;
-import com.jeeplus.modules.syswarning.entity.SysWarning;
-import com.jeeplus.modules.syswarning.dao.SysWarningDao;
-import redis.clients.jedis.Jedis;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 
 /**
  * 系统预警Service
@@ -244,7 +235,6 @@ public class SysWarningService extends CrudService<SysWarningDao, SysWarning> {
 					}else{
 						System.out.println("短信发送失败!");
 					}
-
 				}catch (Exception e){
 					e.printStackTrace();
 					System.out.println("短信发送失败!");

+ 9 - 2
src/main/java/com/jeeplus/modules/workcalendar/service/WorkCalendarTaskService.java

@@ -351,8 +351,8 @@ public class WorkCalendarTaskService  {
     /**
      * 超期未收款发票信息提醒通知(开票后超过1个月没有收款的发票数据)
      */
-    //设置每月15号凌晨30分进行执行
-    @Scheduled(cron= "0 30 0 15 * ?")
+    //设置每天凌晨2点45分进行执行
+    @Scheduled(cron= "0 45 2 * * ?")
     @Transactional(readOnly = false)
     public void getOverDueGatheringInvoiceList() {
         logger.info("-----------超期未收款发票信息提醒通知(开始)------------------");
@@ -614,6 +614,13 @@ public class WorkCalendarTaskService  {
         //查询一级造价师的信息
         List<WorkStaffCertificate> firstCostEngineerList = workStaffCertificateService.getFirstCostEngineerList();
         for (WorkStaffCertificate workStaffCertificate : firstCostEngineerList) {
+
+            //查询是否进行了提交申请,如果提交了申请,也不进行通知
+            Integer submitApplicationsById = workStaffCertificateService.getSubmitApplicationsById(workStaffCertificate.getId());
+            if(submitApplicationsById>0){
+                continue;
+            }
+
             if(null != workStaffCertificate.getValidEndDate()){
                 //如果有使用有效期,则让其进行和当前时间进行判定,提前7天进行提醒
                 // 获取结束时间(数据库取出来的 Date)

+ 7 - 0
src/main/java/com/jeeplus/modules/workinvoice/dao/WorkInvoiceDao.java

@@ -296,4 +296,11 @@ public interface WorkInvoiceDao extends CrudDao<WorkInvoice> {
 	 * @return
 	 */
 	List<WorkInvoice> getByIdList(@Param("idList") List<String> idList);
+
+	/**
+	 * 修改长期未收款通知的时间
+	 * @param workInvoice
+	 * @return
+	 */
+	Integer updateUncollectedInformDate(WorkInvoice workInvoice);
 }

+ 9 - 1
src/main/java/com/jeeplus/modules/workinvoice/entity/WorkInvoice.java

@@ -14,7 +14,6 @@ import com.jeeplus.modules.sys.entity.User;
 import com.jeeplus.modules.sys.entity.Workattachment;
 import com.jeeplus.modules.workclientinfo.entity.WorkClientInfo;
 import com.jeeplus.modules.workinvoicedetail.entity.WorkInvoiceDetail;
-import com.jeeplus.modules.workproject.entity.WorkProject;
 import org.activiti.engine.history.HistoricProcessInstance;
 import org.activiti.engine.repository.ProcessDefinition;
 import org.activiti.engine.runtime.ProcessInstance;
@@ -165,6 +164,7 @@ public class WorkInvoice extends ActEntity<WorkInvoice> {
 
 	private Integer isSmsNotice;//是否需要短信通知(1:需要,0:不需要)
 	private Integer isOmsBilling;//是否接口开票(1:是,0:不是)
+	private Date uncollectedInformDate;//未收款通知时间
 
 
 
@@ -1166,4 +1166,12 @@ public class WorkInvoice extends ActEntity<WorkInvoice> {
 	public void setIsOmsBilling(Integer isOmsBilling) {
 		this.isOmsBilling = isOmsBilling;
 	}
+
+	public Date getUncollectedInformDate() {
+		return uncollectedInformDate;
+	}
+
+	public void setUncollectedInformDate(Date uncollectedInformDate) {
+		this.uncollectedInformDate = uncollectedInformDate;
+	}
 }

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

@@ -13,6 +13,8 @@ import com.jeeplus.common.service.CrudService;
 import com.jeeplus.common.utils.DateUtils;
 import com.jeeplus.common.utils.MenuStatusEnum;
 import com.jeeplus.common.utils.StringUtils;
+import com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo;
+import com.jeeplus.modules.WorkOssNoteInformInfo.service.WorkOssNoteInformInfoService;
 import com.jeeplus.modules.act.service.ActTaskService;
 import com.jeeplus.modules.act.utils.ActUtils;
 import com.jeeplus.modules.projectrecord.entity.ProjectRecords;
@@ -146,6 +148,8 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 	private WorkInvoiceCloudDao workInvoiceCloudDao;
 	@Autowired
 	private UserDao userDao;
+	@Autowired
+	private WorkOssNoteInformInfoService workOssNoteInformInfoService;
 
 	Pattern mobilePattern = Pattern.compile("^1[3-9]\\d{9}$");
 
@@ -3933,6 +3937,37 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 									"待通知",
 									""));
 				}
+
+				//需要修改本次通知的时间,方便7天之后再次通知
+				workInvoice.setUncollectedInformDate(new Date());
+				workInvoiceDao.updateUncollectedInformDate(workInvoice);
+				//需要给发票发起人发送短信通知
+				User user = UserUtils.get(workInvoice.getCreateBy().getId());
+				HashMap<String, Object> hashMap = ALiYunSmsUtil.updateUncollectedInformSms(user.getName(), user.getMobile(), workInvoice.getNumber());
+
+				//获取短信发送内容
+				String smsContent = (String) hashMap.get("smsContent");
+				//获取短信发送结果状态值
+				Integer statusCode = (Integer) hashMap.get("statusCode");
+				//获取短信发送结果
+				String message = (String) hashMap.get("message");
+				//将短信发送信息保存到数据库中
+				WorkOssNoteInformInfo workOssNoteInformInfo = new WorkOssNoteInformInfo();
+				workOssNoteInformInfo.setReceiveUserId(user.getId());
+				workOssNoteInformInfo.setSendTime(new Date());
+				workOssNoteInformInfo.setSendContent(smsContent);
+				workOssNoteInformInfo.setPhone(user.getMobile()==null?"":user.getMobile());
+
+				if(200 == statusCode){
+					workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+					workOssNoteInformInfo.setMessage(message);
+					workOssNoteInformInfo.setSmsModule("开票未收款");
+				}else{
+					workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+					workOssNoteInformInfo.setMessage(message);
+				}
+				workOssNoteInformInfoService.saveRecord(workOssNoteInformInfo);
+
 			}
 
 		}
@@ -4392,6 +4427,29 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 							j.put("message","短信发送失败,错误代码:101,请联系管理员!");
 							j.put("ErrorXml",result);
 						}
+
+
+						//获取短信发送内容
+						String smsContent = (String) result.get("smsContent");
+						//获取短信发送结果
+						String message = (String) result.get("message");
+						//将短信发送信息保存到数据库中
+						WorkOssNoteInformInfo workOssNoteInformInfo = new WorkOssNoteInformInfo();
+						workOssNoteInformInfo.setReceiveUserId(user.getId());
+						workOssNoteInformInfo.setSendTime(new Date());
+						workOssNoteInformInfo.setSendContent(smsContent);
+						workOssNoteInformInfo.setPhone(user.getMobile()==null?"":user.getMobile());
+
+						if(200 == statusCode){
+							workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+							workOssNoteInformInfo.setMessage(message);
+							workOssNoteInformInfo.setSmsModule("数电开票成功");
+						}else{
+							workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+							workOssNoteInformInfo.setMessage(message);
+						}
+						workOssNoteInformInfoService.saveRecord(workOssNoteInformInfo);
+
 					}catch (Exception e){
 						System.out.println("阿里云发送短信失败。失败原因为:" + e.getMessage());
 						logger.error("调用短信接口发生错误", e);  // 记录详细日志
@@ -4536,7 +4594,7 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 			List<User> cwUsers = UserUtils.getByRoleActivityEnnameOnNotCompany("cwygevod",3,cwbOffice.getId(),"5",workInvoice.getCreateBy(),workInvoice.getCompanyId());
 			for (User cwuser : cwUsers) {
 				//查询开票人员的手机号
-				cwuser = userDao.get(workInvoice.getCreateBy().getId());
+				cwuser = userDao.get(cwuser.getId());
 				//user.setMobile("18164266544");
 				if (StringUtils.isNotBlank(cwuser.getMobile()) && mobilePattern.matcher(cwuser.getMobile().trim()).matches() ) {
 					//验证手机号是否已经注册
@@ -4576,6 +4634,30 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 								j.put("message","短信发送失败,错误代码:101,请联系管理员!");
 								j.put("ErrorXml",result);
 							}
+
+
+							//获取短信发送内容
+							String smsContent = (String) result.get("smsContent");
+							//获取短信发送结果
+							String message = (String) result.get("message");
+							//将短信发送信息保存到数据库中
+							WorkOssNoteInformInfo workOssNoteInformInfo = new WorkOssNoteInformInfo();
+							workOssNoteInformInfo.setReceiveUserId(cwuser.getId());
+							workOssNoteInformInfo.setSendTime(new Date());
+							workOssNoteInformInfo.setSendContent(smsContent);
+							workOssNoteInformInfo.setPhone(cwuser.getMobile()==null?"":cwuser.getMobile());
+
+							if(200 == statusCode){
+								workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+								workOssNoteInformInfo.setMessage(message);
+								workOssNoteInformInfo.setSmsModule("数电开票失败");
+							}else{
+								workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+								workOssNoteInformInfo.setMessage(message);
+							}
+							workOssNoteInformInfoService.saveRecord(workOssNoteInformInfo);
+
+
 						}catch (Exception e){
 							System.out.println("阿里云发送短信失败。失败原因为:" + e.getMessage());
 							logger.error("调用短信接口发生错误", e);  // 记录详细日志
@@ -4634,6 +4716,30 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 						j.put("message","短信发送失败,错误代码:101,请联系管理员!");
 						j.put("ErrorXml",result);
 					}
+
+
+					//获取短信发送内容
+					String smsContent = (String) result.get("smsContent");
+					//获取短信发送结果
+					String message = (String) result.get("message");
+					//将短信发送信息保存到数据库中
+					WorkOssNoteInformInfo workOssNoteInformInfo = new WorkOssNoteInformInfo();
+					workOssNoteInformInfo.setReceiveUserId(user.getId());
+					workOssNoteInformInfo.setSendTime(new Date());
+					workOssNoteInformInfo.setSendContent(smsContent);
+					workOssNoteInformInfo.setPhone(user.getMobile()==null?"":user.getMobile());
+
+					if(200 == statusCode){
+						workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+						workOssNoteInformInfo.setMessage(message);
+						workOssNoteInformInfo.setSmsModule("数电开票失败");
+					}else{
+						workOssNoteInformInfo.setStatusCode(String.valueOf(statusCode));
+						workOssNoteInformInfo.setMessage(message);
+					}
+					workOssNoteInformInfoService.saveRecord(workOssNoteInformInfo);
+
+
 				}catch (Exception e){
 					System.out.println("阿里云发送短信失败。失败原因为:" + e.getMessage());
 					logger.error("调用短信接口发生错误", e);  // 记录详细日志

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

@@ -42,4 +42,10 @@ public interface WorkStaffCertificateDao extends CrudDao<WorkStaffCertificate> {
      * @return
      */
     List<WorkStaffCertificate> getFirstCostEngineerList();
+
+    /**
+     * 查询所有的一级造价师信息
+     * @return
+     */
+    Integer getSubmitApplicationsById(String id);
 }

+ 4 - 0
src/main/java/com/jeeplus/modules/workstaff/service/WorkStaffCertificateService.java

@@ -1495,4 +1495,8 @@ public class WorkStaffCertificateService extends CrudService<WorkStaffCertificat
     public List<WorkStaffCertificate> getFirstCostEngineerList(){
         return dao.getFirstCostEngineerList();
     }
+
+    public Integer getSubmitApplicationsById(String id){
+        return dao.getSubmitApplicationsById(id);
+    }
 }

+ 263 - 0
src/main/resources/mappings/modules/SysMenuDictRelation/SysMenuDictRelationDao.xml

@@ -0,0 +1,263 @@
+<?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.SysMenuDictRelation.dao.SysMenuDictRelationDao">
+
+    <sql id="columns">
+        a.id            AS "id",
+        a.dict_value_id AS "dictValueId",
+        a.menu_id       AS "menuId",
+        a.create_by     AS "createBy.id",
+        a.create_date   AS "createDate",
+        a.update_by     AS "updateBy.id",
+        a.update_date   AS "updateDate",
+        a.remarks       AS "remarks",
+        a.del_flag      AS "delFlag"
+    </sql>
+
+    <!-- 单条查询 -->
+    <select id="get" resultType="com.jeeplus.modules.SysMenuDictRelation.entity.SysMenuDictRelation">
+        SELECT <include refid="columns"/>
+        FROM sys_menu_dict_relation a
+        WHERE a.id = #{id}
+    </select>
+
+    <!-- findList -->
+    <select id="findList" resultType="com.jeeplus.modules.SysMenuDictRelation.entity.SysMenuDictRelation">
+        SELECT <include refid="columns"/>
+        FROM sys_menu_dict_relation a
+        WHERE a.del_flag = '0'
+        ORDER BY a.create_date DESC
+    </select>
+
+    <!-- findListByUser -->
+    <select id="findListByUser" resultType="com.jeeplus.modules.SysMenuDictRelation.entity.SysMenuDictRelation">
+        SELECT <include refid="columns"/>
+        FROM sys_menu_dict_relation a
+        WHERE a.del_flag = '0'
+        ORDER BY a.create_date DESC
+    </select>
+
+    <!-- findAllList -->
+    <select id="findAllList" resultType="com.jeeplus.modules.SysMenuDictRelation.entity.SysMenuDictRelation">
+        SELECT <include refid="columns"/>
+        FROM sys_menu_dict_relation a
+        WHERE a.del_flag = '0'
+        ORDER BY a.create_date DESC
+    </select>
+
+    <!-- queryCount -->
+    <select id="queryCount" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM sys_menu_dict_relation a
+        WHERE a.del_flag = '0'
+    </select>
+
+    <!-- findUniqueByProperty -->
+    <select id="findUniqueByProperty" resultType="com.jeeplus.modules.SysMenuDictRelation.entity.SysMenuDictRelation">
+        SELECT <include refid="columns"/>
+        FROM sys_menu_dict_relation a
+        WHERE ${propertyName} = #{value} AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <!-- 插入 -->
+    <insert id="insert">
+        INSERT INTO sys_menu_dict_relation (
+            id, dict_value_id, menu_id,
+            create_by, create_date, update_by, update_date,
+            remarks, del_flag
+        ) VALUES (
+            #{id}, #{dictValueId}, #{menuId},
+            #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate},
+            #{remarks}, #{delFlag}
+        )
+    </insert>
+
+    <!-- 更新 -->
+    <update id="update">
+        UPDATE sys_menu_dict_relation SET
+            dict_value_id = #{dictValueId},
+            menu_id       = #{menuId},
+            update_by     = #{updateBy.id},
+            update_date   = #{updateDate},
+            remarks       = #{remarks}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 物理删除 -->
+    <delete id="delete">
+        DELETE FROM sys_menu_dict_relation WHERE id = #{id}
+    </delete>
+
+    <!-- 逻辑删除 -->
+    <update id="deleteByLogic">
+        UPDATE sys_menu_dict_relation SET
+            del_flag    = '1',
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE id = #{id}
+    </update>
+
+    <!-- ==================== 自定义 SQL ==================== -->
+
+    <!--
+        查询待配置的字典值列表(含已绑定菜单名称,逗号分隔)
+        type_code = 'agenda_project_notify_type' and del_flag = 0
+    -->
+    <select id="findDictValueList" resultType="java.util.Map">
+        SELECT
+            dv.id     AS "id",
+            dv.label  AS "label",
+            dv.value  AS "value",
+            IFNULL(
+                (
+                    SELECT GROUP_CONCAT(m.name ORDER BY m.sort ASC SEPARATOR '、')
+                    FROM sys_menu_dict_relation r
+                    INNER JOIN sys_menu m ON m.id = r.menu_id AND m.del_flag = '0'
+                    WHERE r.dict_value_id = dv.id
+                      AND r.del_flag = '0'
+                ), ''
+            ) AS "menuNames"
+        FROM sys_dict dv
+        WHERE dv.type = 'agenda_project_notify_type'
+          AND dv.del_flag = '0'
+        ORDER BY dv.sort ASC
+    </select>
+
+    <!--
+        查询可选菜单:一级菜单(parent_id='1')和二级菜单(父节点的 parent_id='1')
+        同时返回 level(1=一级, 2=二级)、parentId、parentName 供前端树形渲染
+    -->
+    <select id="findMenuList" resultType="java.util.Map">
+        SELECT
+            m.id                AS "id",
+            m.name              AS "name",
+            m.parent_id         AS "parentId",
+            CASE
+                WHEN m.parent_id = '1' THEN 1
+                ELSE 2
+            END                 AS "level",
+            IFNULL(p.name, '') AS "parentName"
+        FROM sys_menu m
+        LEFT JOIN sys_menu p ON p.id = m.parent_id AND p.del_flag = '0'
+        WHERE m.del_flag = '0'
+          AND (
+              m.parent_id = '1'
+              OR (
+                  m.parent_id != '1'
+                  AND m.parent_id != '0'
+                  AND (
+                      SELECT parent_id FROM sys_menu WHERE id = m.parent_id AND del_flag = '0'
+                  ) = '1'
+              )
+          )
+        ORDER BY
+            m.sort ASC,
+            CASE WHEN m.parent_id = '1' THEN m.id ELSE m.parent_id END ASC,
+            m.parent_id ASC
+    </select>
+
+    <!--
+        根据字典值ID查询已绑定的菜单ID列表
+    -->
+    <select id="findMenuIdsByDictValueId" resultType="java.lang.String">
+        SELECT menu_id
+        FROM sys_menu_dict_relation
+        WHERE dict_value_id = #{dictValueId}
+          AND del_flag = '0'
+    </select>
+
+    <!--
+        逻辑删除指定字典值ID的所有绑定关系
+    -->
+    <delete id="deleteByDictValueId">
+        delete from sys_menu_dict_relation
+        where dict_value_id = #{dictValueId}
+          AND del_flag = '0'
+    </delete>
+
+    <!--
+        批量插入绑定关系
+    -->
+    <insert id="insertBatch">
+        INSERT INTO sys_menu_dict_relation (
+            id, dict_value_id, menu_id,
+            create_by, create_date, update_by, update_date,
+            remarks, del_flag
+        ) VALUES
+        <foreach collection="list" item="item" separator=",">
+            (
+                #{item.id}, #{item.dictValueId}, #{item.menuId},
+                #{item.createBy.id}, #{item.createDate}, #{item.updateBy.id}, #{item.updateDate},
+                #{item.remarks}, #{item.delFlag}
+            )
+        </foreach>
+    </insert>
+
+    <!--
+        代办页面专用:根据用户菜单ID集合查询有权限的字典值列表
+        1. 查询 sys_menu_dict_relation 中 menu_id IN (用户菜单ID)
+        2. 关联 sys_dict 过滤 type = 'agenda_project_notify_type'
+        3. 对字典值去重
+    -->
+    <select id="findDictValuesByMenuIds" resultType="java.util.Map">
+        SELECT DISTINCT
+            dv.id     AS "id",
+            dv.label  AS "label",
+            dv.value  AS "value"
+        FROM sys_dict dv
+        INNER JOIN sys_menu_dict_relation r ON r.dict_value_id = dv.id AND r.del_flag = '0'
+        WHERE dv.type = 'agenda_project_notify_type'
+          AND dv.del_flag = '0'
+          AND r.menu_id IN
+          <foreach collection="menuIds" item="menuId" open="(" separator="," close=")">
+              #{menuId}
+          </foreach>
+        ORDER BY dv.sort ASC
+    </select>
+
+    <!--
+        通知页面:查询待配置的字典値列表(含已绑定菜单名称)
+        type = 'new_project_notify_type' and del_flag = 0
+    -->
+    <select id="findNotifyDictValueList" resultType="java.util.Map">
+        SELECT
+            dv.id     AS "id",
+            dv.label  AS "label",
+            dv.value  AS "value",
+            IFNULL(
+                (
+                    SELECT GROUP_CONCAT(m.name ORDER BY m.sort ASC SEPARATOR '、')
+                    FROM sys_menu_dict_relation r
+                    INNER JOIN sys_menu m ON m.id = r.menu_id AND m.del_flag = '0'
+                    WHERE r.dict_value_id = dv.id
+                      AND r.del_flag = '0'
+                ), ''
+            ) AS "menuNames"
+        FROM sys_dict dv
+        WHERE dv.type = 'new_project_notify_type'
+          AND dv.del_flag = '0'
+        ORDER BY dv.sort ASC
+    </select>
+
+    <!--
+        通知页面专用:根据用户菜单ID集合查询有权限的字典値列表
+        过滤 type = 'new_project_notify_type'
+    -->
+    <select id="findNotifyDictValuesByMenuIds" resultType="java.util.Map">
+        SELECT DISTINCT
+            dv.id     AS "id",
+            dv.label  AS "label",
+            dv.value  AS "value"
+        FROM sys_dict dv
+        INNER JOIN sys_menu_dict_relation r ON r.dict_value_id = dv.id AND r.del_flag = '0'
+        WHERE dv.type = 'new_project_notify_type'
+          AND dv.del_flag = '0'
+          AND r.menu_id IN
+          <foreach collection="menuIds" item="menuId" open="(" separator="," close=")">
+              #{menuId}
+          </foreach>
+        ORDER BY dv.sort ASC
+    </select>
+
+</mapper>

+ 50 - 10
src/main/resources/mappings/modules/WorkKnowledgeBase/WorkKnowledgeBaseShareInfoDao.xml

@@ -7,6 +7,7 @@
         a.tree_node_id  AS "treeNodeId",
         a.file_name     AS "fileName",
         a.file_url      AS "fileUrl",
+        a.name      AS "name",
         a.create_time   AS "createTime",
         a.create_by     AS "createBy.id",
         a.create_date   AS "createDate",
@@ -62,6 +63,7 @@
             a.tree_node_id                                        AS "treeNodeId",
             a.file_name                                           AS "fileName",
             a.file_url                                            AS "fileUrl",
+            a.name AS "name",
             DATE_FORMAT(a.create_time,'%Y-%m-%d %H:%i:%s')       AS "createTime",
             a.create_by                                           AS "createById",
             (SELECT su.name FROM sys_user su WHERE su.id = a.create_by) AS "createByName",
@@ -78,17 +80,34 @@
             ON v.file_id = a.id AND v.del_flag = '0'
         <where>
             a.del_flag = '0'
-            <!-- 固定查询:节点id(通过根节点下所有节点查询) -->
-            <if test="entity.rootId != null and entity.rootId != ''">
+            <!-- 匹配当前选中节点及其所有子节点的数据 -->
+            <if test="entity.treeNodeId != null and entity.treeNodeId != ''">
+                AND a.tree_node_id IN (
+                    SELECT t.id FROM work_knowledge_base_tree_info t
+                    WHERE (t.id = #{entity.treeNodeId}
+                           OR t.parent_ids LIKE CONCAT('%,', #{entity.treeNodeId}, ',%')
+                           OR t.parent_ids LIKE CONCAT('%,', #{entity.treeNodeId})
+                           OR t.parent_ids LIKE CONCAT(#{entity.treeNodeId}, ',%'))
+                      AND t.del_flag = '0'
+                )
+            </if>
+            <!-- 兆底:若无treeNodeId但有rootId,则查根节点下所有节点 -->
+            <if test="(entity.treeNodeId == null or entity.treeNodeId == '') and entity.rootId != null and entity.rootId != ''">
                 AND a.tree_node_id IN (
                     SELECT t.id FROM work_knowledge_base_tree_info t
                     WHERE (t.id = #{entity.rootId} OR t.root_id = #{entity.rootId})
                       AND t.del_flag = '0'
                 )
             </if>
-            <!-- 固定查询:文件名模糊查询 -->
-            <if test="entity.fileName != null and entity.fileName != ''">
-                AND a.file_name LIKE CONCAT('%', #{entity.fileName}, '%')
+            <if test="entity.name != null and entity.name != ''">
+                AND a.name LIKE CONCAT('%', #{entity.name}, '%')
+            </if>
+            <!-- 创建时间区间查询 -->
+            <if test="entity.beginDate != null and entity.beginDate != ''">
+                AND a.create_date &gt;= #{entity.beginDate}
+            </if>
+            <if test="entity.endDate != null and entity.endDate != ''">
+                AND a.create_date &lt;= CONCAT(#{entity.endDate}, ' 23:59:59')
             </if>
             <!-- 动态字段查询条件:EXISTS 子查询(禁止写在主WHERE中) -->
             <if test="dynamicConditions != null">
@@ -120,15 +139,35 @@
         FROM work_knowledge_base_share_info a
         <where>
             a.del_flag = '0'
-            <if test="entity.rootId != null and entity.rootId != ''">
+            <!-- 匹配当前选中节点及其所有子节点的数据 -->
+            <if test="entity.treeNodeId != null and entity.treeNodeId != ''">
+                AND a.tree_node_id IN (
+                    SELECT t.id FROM work_knowledge_base_tree_info t
+                    WHERE (t.id = #{entity.treeNodeId}
+                           OR t.parent_ids LIKE CONCAT('%,', #{entity.treeNodeId}, ',%')
+                           OR t.parent_ids LIKE CONCAT('%,', #{entity.treeNodeId})
+                           OR t.parent_ids LIKE CONCAT(#{entity.treeNodeId}, ',%'))
+                      AND t.del_flag = '0'
+                )
+            </if>
+            <!-- 兆底:若无treeNodeId但有rootId,则查根节点下所有节点 -->
+            <if test="(entity.treeNodeId == null or entity.treeNodeId == '') and entity.rootId != null and entity.rootId != ''">
                 AND a.tree_node_id IN (
                     SELECT t.id FROM work_knowledge_base_tree_info t
                     WHERE (t.id = #{entity.rootId} OR t.root_id = #{entity.rootId})
                       AND t.del_flag = '0'
                 )
             </if>
-            <if test="entity.fileName != null and entity.fileName != ''">
-                AND a.file_name LIKE CONCAT('%', #{entity.fileName}, '%')
+            <!-- 固定查询:文件名模糊查询 -->
+            <if test="entity.name != null and entity.name != ''">
+                AND a.name LIKE CONCAT('%', #{entity.name}, '%')
+            </if>
+            <!-- 创建时间区间查询 -->
+            <if test="entity.beginDate != null and entity.beginDate != ''">
+                AND a.create_date &gt;= #{entity.beginDate}
+            </if>
+            <if test="entity.endDate != null and entity.endDate != ''">
+                AND a.create_date &lt;= CONCAT(#{entity.endDate}, ' 23:59:59')
             </if>
             <!-- 动态字段查询条件:EXISTS 子查询 -->
             <if test="dynamicConditions != null">
@@ -178,10 +217,10 @@
     <!-- 插入 -->
     <insert id="insert">
         INSERT INTO work_knowledge_base_share_info (
-            id, tree_node_id, file_name, file_url, create_time,
+            id, tree_node_id, file_name, file_url, name, create_time,
             create_by, create_date, update_by, update_date, remarks, del_flag
         ) VALUES (
-            #{id}, #{treeNodeId}, #{fileName}, #{fileUrl}, NOW(),
+            #{id}, #{treeNodeId}, #{fileName}, #{fileUrl}, #{name}, NOW(),
             #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks}, #{delFlag}
         )
     </insert>
@@ -191,6 +230,7 @@
         UPDATE work_knowledge_base_share_info SET
             file_name   = #{fileName},
             file_url    = #{fileUrl},
+            name    = #{name},
             update_by   = #{updateBy.id},
             update_date = #{updateDate},
             remarks     = #{remarks}

+ 146 - 0
src/main/resources/mappings/modules/WorkOssNoteInformInfo/WorkOssNoteInformInfoDao.xml

@@ -0,0 +1,146 @@
+<?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.WorkOssNoteInformInfo.dao.WorkOssNoteInformInfoDao">
+
+    <sql id="ossNoteColumns">
+        a.id                  AS "id",
+        a.receive_user_id     AS "receiveUserId",
+        su.name   AS "receiveUserName",
+        a.send_time           AS "sendTime",
+        a.send_content        AS "sendContent",
+        a.sms_type            AS "smsType",
+        a.phone               AS "phone",
+        a.sms_module          AS "smsModule",
+        a.create_by           AS "createBy.id",
+        a.create_date         AS "createDate",
+        a.update_by           AS "updateBy.id",
+        a.update_date         AS "updateDate",
+        a.remarks             AS "remarks",
+        a.status_code             AS "statusCode",
+        a.message             AS "message",
+        a.del_flag            AS "delFlag"
+    </sql>
+
+    <!-- 根据id获取单条 -->
+    <select id="get" resultType="com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo">
+        SELECT <include refid="ossNoteColumns"/>
+        FROM work_oss_note_inform_info a
+        left join sys_user su on su.id = a.receive_user_id
+        WHERE a.id = #{id}
+    </select>
+
+    <!-- 列表查询(含条件过滤) -->
+    <select id="findList" resultType="com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo">
+        SELECT <include refid="ossNoteColumns"/>
+        FROM work_oss_note_inform_info a
+        left join sys_user su on su.id = a.receive_user_id
+        <where>
+            a.del_flag = #{DEL_FLAG_NORMAL}
+
+            <if test="(receiveUserId != null and receiveUserId != '') or (receiveUserName != null and receiveUserName != '')">
+                AND (a.receive_user_id = #{receiveUserId} or su.name like concat('%',#{receiveUserName},'%'))
+            </if>
+            <!-- 发送时间区间 -->
+            <if test="sendTimeStart != null and sendTimeStart != ''">
+                AND a.send_time &gt;= #{sendTimeStart}
+            </if>
+            <if test="sendTimeEnd != null and sendTimeEnd != ''">
+                AND a.send_time &lt; DATE_ADD(#{sendTimeEnd}, INTERVAL 1 DAY)
+            </if>
+            <!-- 发送内容模糊查询 -->
+            <if test="sendContent != null and sendContent != ''">
+                AND a.send_content LIKE CONCAT('%',#{sendContent},'%')
+            </if>
+            <!-- 发送手机号 -->
+            <if test="phone != null and phone != ''">
+                AND a.phone LIKE CONCAT('%',#{phone},'%')
+            </if>
+            <!-- 所属模块精确匹配 -->
+            <if test="smsModule != null and smsModule != ''">
+                AND a.sms_module LIKE CONCAT('%',#{smsModule},'%')
+            </if>
+            <!-- 所属模块精确匹配 -->
+            <if test="message != null and message != ''">
+                AND a.message LIKE CONCAT('%',#{message},'%')
+            </if>
+            <!-- 所属模块精确匹配 -->
+            <if test="statusCode != null and statusCode != ''">
+                AND a.status_code LIKE CONCAT('%',#{statusCode},'%')
+            </if>
+        </where>
+        ORDER BY a.send_time DESC, a.create_date DESC
+    </select>
+
+    <select id="findAllList" resultType="com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo">
+        SELECT <include refid="ossNoteColumns"/>
+        FROM work_oss_note_inform_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.send_time DESC, a.create_date DESC
+    </select>
+
+    <select id="findListByUser" resultType="com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo">
+        SELECT <include refid="ossNoteColumns"/>
+        FROM work_oss_note_inform_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+        ORDER BY a.send_time DESC, a.create_date DESC
+    </select>
+
+    <select id="findUniqueByProperty" resultType="com.jeeplus.modules.WorkOssNoteInformInfo.entity.WorkOssNoteInformInfo">
+        SELECT <include refid="ossNoteColumns"/>
+        FROM work_oss_note_inform_info a
+        WHERE ${propertyName} = #{value} AND a.del_flag = '0'
+        LIMIT 1
+    </select>
+
+    <select id="queryCount" resultType="java.lang.Integer">
+        SELECT COUNT(1)
+        FROM work_oss_note_inform_info a
+        WHERE a.del_flag = #{DEL_FLAG_NORMAL}
+    </select>
+
+    <!-- 插入 -->
+    <insert id="insert">
+        INSERT INTO work_oss_note_inform_info (
+            id, receive_user_id, receive_user_name, send_time,phone, status_code, message,
+            send_content, sms_type, sms_module,
+            create_by, create_date, update_by, update_date, remarks, del_flag
+        ) VALUES (
+            #{id}, #{receiveUserId}, #{receiveUserName}, #{sendTime}, #{phone}, #{statusCode}, #{message},
+            #{sendContent}, #{smsType}, #{smsModule},
+            #{createBy.id}, #{createDate}, #{updateBy.id}, #{updateDate}, #{remarks}, #{delFlag}
+        )
+    </insert>
+
+    <!-- 更新 -->
+    <update id="update">
+        UPDATE work_oss_note_inform_info SET
+            receive_user_id   = #{receiveUserId},
+            receive_user_name = #{receiveUserName},
+            send_time         = #{sendTime},
+            send_content      = #{sendContent},
+            phone             = #{phone},
+            status_code = #{statusCode},
+            message = #{message},
+            sms_type          = #{smsType},
+            sms_module        = #{smsModule},
+            update_by         = #{updateBy.id},
+            update_date       = #{updateDate},
+            remarks           = #{remarks}
+        WHERE id = #{id}
+    </update>
+
+    <!-- 物理删除(不建议使用) -->
+    <delete id="delete">
+        DELETE FROM work_oss_note_inform_info WHERE id = #{id}
+    </delete>
+
+    <!-- 逻辑删除 -->
+    <update id="deleteByLogic">
+        UPDATE work_oss_note_inform_info SET
+            del_flag    = #{DEL_FLAG_DELETE},
+            update_by   = #{updateBy.id},
+            update_date = #{updateDate}
+        WHERE id = #{id}
+    </update>
+
+</mapper>

+ 16 - 0
src/main/resources/mappings/modules/sys/UserDao.xml

@@ -245,6 +245,22 @@
 				and a.name like concat('%',#{name},'%')
 			</if>
 		</where>
+		limit 1
+	</select>
+
+	<!-- 根据登录名查询用户 -->
+	<select id="getUserByMobile" resultType="User" parameterType="User">
+		SELECT
+		<include refid="userColumns"/>
+		FROM sys_user a
+		LEFT JOIN sys_office s ON s.id = a.company_id
+		LEFT JOIN sys_office o ON o.id = a.office_id
+		LEFT JOIN sys_office bo ON bo.id = o.branch_office
+		<where>
+			<if test="mobile != null and mobile != ''">
+				and a.mobile like concat('%',#{mobile},'%')
+			</if>
+		</where>
 	</select>
 
 	<!-- 分页查询用户信息 -->

+ 16 - 2
src/main/resources/mappings/modules/workinvoice/WorkInvoiceDao.xml

@@ -3188,13 +3188,20 @@
 		datediff(now(), a.invoice_date) as adventDate,
 		a.red_invoice_flag as "redInvoiceFlag",
 		a.red_invoice_relevancy_id as "redInvoiceRelevancyId",
-		a.red_invoice_relevancy_number as "redInvoiceRelevancyNumber"
+		a.red_invoice_relevancy_number as "redInvoiceRelevancyNumber",
+		a.uncollected_inform_date as "uncollectedInformDate"
 		from work_invoice a
 		<where>
 			a.invoice_date &lt;= #{invoiceDate}
 			and a.del_flag = 0
 			and (a.receipt_money_date is null and a.receipt_money = 0)
-			and invoice_state != 1 and invoice_state != 2 and invoice_state != 3 and invoice_state != 4 and invoice_state != 7
+			and invoice_state not in (1,2,3,4,7)
+
+			and (
+			a.uncollected_inform_date is null
+			OR
+			datediff(curdate(), a.uncollected_inform_date) >= 7
+			)
 		</where>
 	</select>
 
@@ -3579,4 +3586,11 @@
 		</where>
 	</select>
 
+
+	<update id="updateUncollectedInformDate">
+		UPDATE work_invoice SET
+			uncollected_inform_date = #{uncollectedInformDate}
+		WHERE id = #{id}
+	</update>
+
 </mapper>

+ 4 - 1
src/main/resources/mappings/modules/workprojectnotify/WorkProjectNotifyDao.xml

@@ -275,7 +275,10 @@
 			</choose>
 		</where>
 
-		ORDER BY a.update_date DESC, a.exigency desc
+		ORDER BY
+		CASE WHEN a.type = 216 THEN 0 ELSE 1 END ASC,
+		a.update_date DESC,
+		a.exigency desc
 		<choose>
 			<!--<when test="page !=null and page.orderBy != null and page.orderBy != ''">
 				ORDER BY ${page.orderBy}

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

@@ -271,5 +271,14 @@
 		</where>
 	</select>
 
+	<select id="getSubmitApplicationsById" resultType="java.lang.Integer" >
+		SELECT
+		count(1)
+		FROM work_staff_achives_log a
+		<where>
+			a.del_flag = 0 and son_id = #{id} and state = 1
+		</where>
+	</select>
+
 
 </mapper>

+ 289 - 0
src/main/webapp/WEB-INF/tags/table/singleAttachmentManager.tag

@@ -0,0 +1,289 @@
+<%@ include file="/webpage/include/taglib.jsp"%>
+<%@ tag pageEncoding="UTF-8"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
+
+<%-- 单文件上传组件:最多上传1个文件,去除收藏调用功能 --%>
+
+<%-- 可配置参数定义 --%>
+<%@ attribute name="title" type="java.lang.String" description="附件区域标题"%>
+<%@ attribute name="titleDescribe" type="java.lang.String" description="附件区域描述"%>
+<%@ attribute name="addBtnText" type="java.lang.String" description="添加附件按钮文本"%>
+<%@ attribute name="baseId" type="java.lang.String" required="true" description="组件唯一标识前缀(避免页面冲突)"%>
+<%@ attribute name="attachments" type="java.util.List" required="true" description="附件列表数据(必填)"%>
+<%@ attribute name="uploadMode" type="java.lang.Integer" description="上传模式(1:百度云,2:阿里云)"%>
+<%@ attribute name="picturePreviewUrl" type="java.lang.String" description="图片预览接口地址"%>
+<%@ attribute name="attachmentFlag" type="java.lang.String" description="附件标识" %>
+<%@ attribute name="storeAs" type="java.lang.String" description="存储路径标识" %>
+<%@ attribute name="fileHandlerFuncName" type="java.lang.String" description="文件选择处理函数名" %>
+
+<%-- 初始化默认值 --%>
+<c:set var="ctx" value="${pageContext.request.contextPath}" />
+<c:if test="${empty title}"><c:set var="title" value="附件信息" /></c:if>
+<c:if test="${empty titleDescribe}"><c:set var="titleDescribe" value="" /></c:if>
+<c:if test="${empty addBtnText}"><c:set var="addBtnText" value="上传文件" /></c:if>
+<c:if test="${empty uploadMode}"><c:set var="uploadMode" value="2" /></c:if>
+<c:if test="${empty picturePreviewUrl}"><c:set var="picturePreviewUrl" value="${pageContext.request.contextPath}${fns:getAdminPath()}/sys/picturepreview/picturePreview?url=" /></c:if>
+<c:if test="${empty attachmentFlag}"><c:set var="attachmentFlag" value="6" /></c:if>
+<c:if test="${empty storeAs}"><c:set var="storeAs" value="wrkReimbursement" /></c:if>
+<c:if test="${empty fileHandlerFuncName}"><c:set var="fileHandlerFuncName" value="insertTitle" /></c:if>
+
+<%-- 已有附件数量(用于初始化按钮显示状态) --%>
+<c:set var="attachmentCount" value="${fn:length(attachments)}" />
+
+<%-- 组件HTML结构 --%>
+<div class="form-group layui-row">
+    <%-- 标题区域 --%>
+    <div class="form-group-label"><h2>${title}<span style="color: red;font-size: 14px;">${titleDescribe}</span></h2></div>
+
+    <%-- 上传按钮区域(已有1个附件时隐藏) --%>
+    <div class="layui-item nav-btns">
+        <a id="${baseId}_btn" class="nav-btn nav-btn-add" title="${addBtnText}"
+           style="font-size:14px;<c:if test="${attachmentCount >= 1}">display:none;</c:if>">
+            <i class="fa fa-plus"></i>&nbsp;${addBtnText}
+        </a>
+    </div>
+
+    <%-- 上传进度条(默认隐藏) --%>
+    <div id="addFile_${baseId}" style="display: none" class="upload-progress">
+        <span id="fileName_${baseId}"></span>
+        <b><span id="baifenbi_${baseId}"></span></b>
+        <div class="progress">
+            <div id="jindutiao_${baseId}" class="progress-bar" style="width: 0%" aria-valuenow="0"></div>
+        </div>
+    </div>
+
+    <%-- 文件选择框(隐藏,通过上传按钮触发,不允许多选) --%>
+    <input
+            id="${baseId}_file"
+            type="file"
+            name="${baseId}_file"
+            style="display: none;"
+            onChange="if(this.value)${fileHandlerFuncName}(this.value);"
+    />
+    <span id="${baseId}_title"></span>
+
+    <%-- 附件列表表格 --%>
+    <div class="layui-item layui-col-xs12" style="padding:0 16px;">
+        <table id="${baseId}_upTable" class="table table-bordered table-condensed details">
+            <thead>
+            <tr>
+                <th>文件预览</th>
+                <th>上传人</th>
+                <th>上传时间</th>
+                <th>文件大小(MB)</th>
+                <th width="200px">操作</th>
+            </tr>
+            </thead>
+            <tbody id="file_${baseId}">
+            <c:forEach items="${attachments}" var="attach" varStatus="status">
+                <tr>
+                    <%-- 文件预览(根据文件类型和上传模式显示不同内容) --%>
+                    <c:choose>
+                        <%-- 阿里云上传模式(uploadMode=2) --%>
+                        <c:when test="${uploadMode == 2}">
+                            <c:choose>
+                                <c:when test="${fn:containsIgnoreCase(attach.attachmentName,'jpg')
+                                           or fn:containsIgnoreCase(attach.attachmentName,'png')
+                                           or fn:containsIgnoreCase(attach.attachmentName,'gif')
+                                           or fn:containsIgnoreCase(attach.attachmentName,'bmp')
+                                           or fn:containsIgnoreCase(attach.attachmentName,'jpeg')}">
+                                    <td>
+                                        <img src="${attach.temporaryUrl}" width="50" height="50" onclick="openPreview('${attach.temporaryUrl}',5)" alt="${attach.attachmentName}">
+                                    </td>
+                                </c:when>
+                                <c:otherwise>
+                                    <c:choose>
+                                        <c:when test="${fn:containsIgnoreCase(attach.attachmentName,'pdf')}">
+                                            <td>
+                                                <a class="attention-info" href="javascript:void(0)"
+                                                   onclick="openPreview('${attach.temporaryUrl}',1)">${attach.attachmentName}</a>
+                                            </td>
+                                        </c:when>
+                                        <c:when test="${fn:containsIgnoreCase(attach.attachmentName,'rar')
+                                                           or fn:containsIgnoreCase(attach.attachmentName,'zip')
+                                                           or fn:containsIgnoreCase(attach.attachmentName,'jar')
+                                                           or fn:containsIgnoreCase(attach.attachmentName,'7z')}">
+                                            <td>
+                                                <a class="attention-info" href="javascript:void(0)"
+                                                   onclick="openPreview('${attach.temporaryUrl}',1)">${attach.attachmentName}</a>
+                                            </td>
+                                        </c:when>
+                                        <c:otherwise>
+                                            <td>
+                                                <a class="attention-info" href="javascript:void(0)"
+                                                   onclick="openPreview('${attach.temporaryUrl}',2)">${attach.attachmentName}</a>
+                                            </td>
+                                        </c:otherwise>
+                                    </c:choose>
+                                </c:otherwise>
+                            </c:choose>
+                        </c:when>
+                        <%-- 百度云上传模式(uploadMode=1) --%>
+                        <c:otherwise>
+                            <c:choose>
+                                <c:when test="${fn:containsIgnoreCase(attach.attachmentName,'jpg')
+                                               or fn:containsIgnoreCase(attach.attachmentName,'png')
+                                               or fn:containsIgnoreCase(attach.attachmentName,'gif')
+                                               or fn:containsIgnoreCase(attach.attachmentName,'bmp')
+                                               or fn:containsIgnoreCase(attach.attachmentName,'jpeg')}">
+                                    <td>
+                                        <img src="${attach.temporaryUrl}" width="50" height="50" onclick="openDialogView('预览','${picturePreviewUrl}${attach.temporaryUrl}','90%','90%')" alt="${attach.attachmentName}">
+                                    </td>
+                                </c:when>
+                                <c:otherwise>
+                                    <c:choose>
+                                        <c:when test="${fn:containsIgnoreCase(attach.attachmentName,'pdf')}">
+                                            <td>
+                                                <a class="attention-info" href="javascript:void(0)"
+                                                   onclick="openPreview('${attach.url}',1)">${attach.attachmentName}</a>
+                                            </td>
+                                        </c:when>
+                                        <c:when test="${fn:containsIgnoreCase(attach.attachmentName,'rar')
+                                                       or fn:containsIgnoreCase(attach.attachmentName,'zip')
+                                                       or fn:containsIgnoreCase(attach.attachmentName,'jar')
+                                                       or fn:containsIgnoreCase(attach.attachmentName,'7z')}">
+                                            <td>
+                                                <a class="attention-info" href="javascript:void(0)"
+                                                   onclick="openPreview('${attach.url}',1)">${attach.attachmentName}</a>
+                                            </td>
+                                        </c:when>
+                                        <c:otherwise>
+                                            <td>
+                                                <a class="attention-info" href="javascript:void(0)"
+                                                   onclick="openPreview('${attach.url}',2)">${attach.attachmentName}</a>
+                                            </td>
+                                        </c:otherwise>
+                                    </c:choose>
+                                </c:otherwise>
+                            </c:choose>
+                        </c:otherwise>
+                    </c:choose>
+
+                    <%-- 上传人 --%>
+                    <td>${attach.createBy.name}</td>
+
+                    <%-- 上传时间 --%>
+                    <td><fmt:formatDate value="${attach.createDate}" type="both"/></td>
+
+                    <%-- 文件大小 --%>
+                    <td>${attach.fileSize}</td>
+
+                    <%-- 操作按钮(下载/删除) --%>
+                    <td class="op-td">
+                        <div class="op-btn-box">
+                            <%-- 下载按钮 --%>
+                            <c:choose>
+                                <c:when test="${uploadMode == 2}">
+                                    <c:choose>
+                                        <c:when test="${fn:containsIgnoreCase(attach.attachmentName,'pdf')}">
+                                            <a href="javascript:location.href='${pageContext.request.contextPath}${fns:getAdminPath()}/workfullmanage/workFullManage/downLoadAttach?file='+encodeURIComponent('${attach.url}');"
+                                               class="op-btn op-btn-download">
+                                                <i class="fa fa-download"></i>&nbsp;下载
+                                            </a>
+                                        </c:when>
+                                        <c:when test="${fn:containsIgnoreCase(attach.attachmentName,'xml')}">
+                                            <a href="javascript:location.href='${pageContext.request.contextPath}${fns:getAdminPath()}/workfullmanage/workFullManage/downLoadAttach?file='+encodeURIComponent('${attach.url}');"
+                                               class="op-btn op-btn-download">
+                                                <i class="fa fa-download"></i>&nbsp;下载
+                                            </a>
+                                        </c:when>
+                                        <c:otherwise>
+                                            <a href="${attach.temporaryUrl}" class="op-btn op-btn-download">
+                                                <i class="fa fa-download"></i>&nbsp;下载
+                                            </a>
+                                        </c:otherwise>
+                                    </c:choose>
+                                </c:when>
+                                <c:otherwise>
+                                    <a href="javascript:location.href='${pageContext.request.contextPath}${fns:getAdminPath()}/workfullmanage/workFullManage/downLoadAttach?file='+encodeURIComponent('${attach.url}');"
+                                       class="op-btn op-btn-download">
+                                        <i class="fa fa-download"></i>&nbsp;下载
+                                    </a>
+                                </c:otherwise>
+                            </c:choose>
+
+                            <%-- 删除按钮(仅上传者可见) --%>
+                            <c:if test="${attach.createBy.id eq fns:getUser().id}">
+                                <a href="javascript:void(0)"
+                                   onclick="deleteFileFromAliyun(this,'${pageContext.request.contextPath}${fns:getAdminPath()}/sys/workattachment/deleteFileFromAliyun?url=${attach.url}&id=${attach.id}&type=2','addFile')"
+                                   class="op-btn op-btn-delete">
+                                    <i class="fa fa-trash"></i>&nbsp;删除
+                                </a>
+                            </c:if>
+                        </div>
+                    </td>
+                </tr>
+            </c:forEach>
+            </tbody>
+        </table>
+    </div>
+</div>
+
+<%-- 组件初始化脚本 --%>
+<script type="text/javascript">
+    // 为上传按钮绑定点击事件
+    document.getElementById('${baseId}_btn').addEventListener('click', function() {
+        document.getElementById('${baseId}_file').click();
+    });
+
+    // 单文件上传处理函数(最多1个文件)
+    function ${fileHandlerFuncName}(tValue) {
+        var existCount = document.getElementById('file_${baseId}').rows.length;
+        var fileInput = document.getElementById('${baseId}_file');
+        var files = fileInput.files;
+
+        if (existCount >= 1) {
+            layer.msg('最多只能上传1个文件,请删除现有文件后再上传。', {icon: 2});
+            fileInput.value = '';
+            return;
+        }
+
+        var attachmentFlag = '${attachmentFlag}';
+        var storeAs = '${storeAs}';
+        var uploadPath = 'http://gangwan-app.oss-cn-hangzhou.aliyuncs.com/' + storeAs;
+        var divId = '_${baseId}';
+
+        for (var i = 0; i < files.length; i++) {
+            var file = files[i];
+            var attachmentId = '';
+            document.getElementById('addFile' + divId).style.display = 'block';
+            multipartUploadWithStsOnFileSize(storeAs, file, attachmentId, attachmentFlag, uploadPath, divId, existCount);
+        }
+
+        // 上传后延迟检查按钮状态
+        setTimeout(function() {
+            checkSingleUploadBtn_${baseId}();
+        }, 1500);
+    }
+
+    // 检查并控制上传按钮显示状态
+    function checkSingleUploadBtn_${baseId}() {
+        var existCount = document.getElementById('file_${baseId}').rows.length;
+        var btn = document.getElementById('${baseId}_btn');
+        if (existCount >= 1) {
+            btn.style.display = 'none';
+        } else {
+            btn.style.display = '';
+        }
+    }
+
+    // 监听删除按钮,删除后重新显示上传按钮
+    (function() {
+        var tbody = document.getElementById('file_${baseId}');
+        tbody.addEventListener('click', function(e) {
+            var target = e.target;
+            // 找到最近的 op-btn-delete
+            while (target && target !== tbody) {
+                if (target.classList && target.classList.contains('op-btn-delete')) {
+                    setTimeout(function() {
+                        checkSingleUploadBtn_${baseId}();
+                    }, 500);
+                    break;
+                }
+                target = target.parentNode;
+            }
+        });
+    })();
+</script>

+ 0 - 1
src/main/webapp/static/oss/ossupload.js

@@ -3535,7 +3535,6 @@ function multipartUploadWithStsOnFileSize(storeAs, file,attachmentId,attachmentF
         });
         storeAs = "attachment-file/" + storeAs +"/"+today+new Date().getTime()+ file.name;
 
-        console.log("cpt",cpt)
         if(cpt == 1){
             multitestFlag(client,storeAs, file,attachmentId,attachmentFlag,uploadPath,divId,size, cpt,"",prefix);
         } else {

+ 313 - 0
src/main/webapp/webpage/modules/SysMenuDictRelation/sysMenuDictRelationForm.jsp

@@ -0,0 +1,313 @@
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@ include file="/webpage/include/taglib.jsp"%>
+<html>
+<head>
+    <title>修改菜单绑定</title>
+    <meta name="decorator" content="default"/>
+    <style>
+        .form-info {
+            background: #f5f7fa;
+            border-radius: 4px;
+            padding: 10px 16px;
+            margin-bottom: 14px;
+            font-size: 13px;
+            color: #555;
+        }
+        .form-info span {
+            font-weight: bold;
+            color: #333;
+        }
+        .form-title {
+            font-size: 14px;
+            font-weight: bold;
+            margin-bottom: 10px;
+            color: #333;
+        }
+        /* 树形容器 */
+        .menu-tree {
+            overflow-y: auto;
+            border: 1px solid #e0e0e0;
+            border-radius: 4px;
+            padding: 8px 4px;
+            background: #fff;
+        }
+        /* 一级节点行 */
+        .tree-node-l1 {
+            display: flex;
+            align-items: center;
+            padding: 5px 8px;
+            cursor: pointer;
+            user-select: none;
+            border-radius: 3px;
+        }
+        .tree-node-l1:hover { background: #f0f4ff; }
+        /* 折叠箭头 */
+        .tree-arrow {
+            display: inline-block;
+            width: 16px;
+            text-align: center;
+            font-size: 11px;
+            color: #999;
+            margin-right: 4px;
+            transition: transform 0.15s;
+            flex-shrink: 0;
+        }
+        .tree-arrow.open { transform: rotate(90deg); }
+        /* 一级节点复选框 + 名称 */
+        .tree-node-l1 label {
+            display: flex;
+            align-items: center;
+            cursor: pointer;
+            font-size: 13px;
+            font-weight: bold;
+            color: #333;
+            flex: 1;
+        }
+        .tree-node-l1 label input { margin-right: 6px; }
+        /* 子节点容器 */
+        .tree-children {
+            display: none;
+            padding-left: 28px;
+        }
+        .tree-children.open { display: block; }
+        /* 二级节点行 */
+        .tree-node-l2 {
+            display: flex;
+            align-items: center;
+            padding: 4px 8px;
+            border-radius: 3px;
+        }
+        .tree-node-l2:hover { background: #f5f7fa; }
+        .tree-node-l2 label {
+            display: flex;
+            align-items: center;
+            cursor: pointer;
+            font-size: 13px;
+            color: #444;
+        }
+        .tree-node-l2 label input { margin-right: 6px; }
+        /* 无子节点时的叶子图标 */
+        .tree-leaf-icon {
+            display: inline-block;
+            width: 16px;
+            text-align: center;
+            font-size: 10px;
+            color: #ccc;
+            margin-right: 4px;
+            flex-shrink: 0;
+        }
+    </style>
+</head>
+<body>
+<div class="wrapper wrapper-content" style="padding:18px;">
+    <input type="hidden" id="dictValueId" value="${dictValueId}"/>
+
+    <div class="form-info">
+        字典标签:<span>${dictLabel}</span>&nbsp;&nbsp;&nbsp;
+        字典值:<span>${dictValue}</span>
+    </div>
+
+    <div class="form-title">请选择要绑定的菜单(可多选):</div>
+
+    <%-- 将服务端数据序列化为 JS 数组,由 JS 负责渲染树 --%>
+    <script>
+        var menuData = [
+            <c:forEach items="${menuList}" var="menu" varStatus="s">
+            {
+                id: "${menu.id}",
+                name: "${menu.name}",
+                parentId: "${menu.parentId}",
+                level: ${menu.level}
+            }<c:if test="${!s.last}">,</c:if>
+            </c:forEach>
+        ];
+
+        var boundIds = [
+            <c:forEach items="${boundMenuIds}" var="mid" varStatus="s">
+            "${mid}"<c:if test="${!s.last}">,</c:if>
+            </c:forEach>
+        ];
+    </script>
+
+    <div class="menu-tree" id="menuTree">
+        <span style="color:#aaa;font-size:13px;">加载中...</span>
+    </div>
+
+    <div style="margin-top:10px;color:#aaa;font-size:12px;">
+        提示:不勾选任何菜单时,该字典值在待办页面将对所有人不可见。
+    </div>
+</div>
+<script>
+    /**
+     * 精确判断某 id 是否在 boundIds 中
+     */
+    function isBound(id) {
+        for (var i = 0; i < boundIds.length; i++) {
+            if (boundIds[i] === id) return true;
+        }
+        return false;
+    }
+
+    /**
+     * 渲染树形菜单
+     * 结构:一级菜单作为父节点(可展开/折叠),其下二级菜单作为子节点
+     * 一级节点自身也可以被勾选
+     */
+    function renderMenuTree() {
+        var tree = document.getElementById('menuTree');
+        tree.innerHTML = '';
+
+        if (!menuData || menuData.length === 0) {
+            tree.innerHTML = '<span style="color:#aaa;">暂无可选菜单</span>';
+            return;
+        }
+
+        // 按 parentId 分组,构造 map:parentId -> [children]
+        var childrenMap = {};   // key: 一级菜单id -> [二级菜单列表]
+        var level1List = [];
+
+        for (var i = 0; i < menuData.length; i++) {
+            var item = menuData[i];
+            if (item.level === 1) {
+                level1List.push(item);
+                if (!childrenMap[item.id]) {
+                    childrenMap[item.id] = [];
+                }
+            }
+        }
+        for (var j = 0; j < menuData.length; j++) {
+            var item2 = menuData[j];
+            if (item2.level === 2) {
+                if (!childrenMap[item2.parentId]) {
+                    childrenMap[item2.parentId] = [];
+                }
+                childrenMap[item2.parentId].push(item2);
+            }
+        }
+
+        // 构建 DOM
+        for (var k = 0; k < level1List.length; k++) {
+            var l1 = level1List[k];
+            var children = childrenMap[l1.id] || [];
+            var hasChildren = children.length > 0;
+            var l1Checked = isBound(l1.id) ? 'checked' : '';
+
+            // 一级节点行
+            var nodeDiv = document.createElement('div');
+            nodeDiv.className = 'tree-node-l1';
+            nodeDiv.setAttribute('data-id', l1.id);
+
+            // 折叠箭头(有子节点才显示)
+            var arrowSpan = document.createElement('span');
+            arrowSpan.className = 'tree-arrow';
+            arrowSpan.innerHTML = hasChildren ? '&#9658;' : '&nbsp;';
+
+            // 复选框 + 名称
+            var l1Label = document.createElement('label');
+            l1Label.innerHTML = '<input type="checkbox" name="menuIds" value="' + l1.id + '" ' + l1Checked + '/> ' + escapeHtml(l1.name);
+
+            nodeDiv.appendChild(arrowSpan);
+            nodeDiv.appendChild(l1Label);
+
+            // 子节点容器
+            var childrenDiv = document.createElement('div');
+            childrenDiv.className = 'tree-children';
+
+            for (var m = 0; m < children.length; m++) {
+                var l2 = children[m];
+                var l2Checked = isBound(l2.id) ? 'checked' : '';
+
+                var l2Div = document.createElement('div');
+                l2Div.className = 'tree-node-l2';
+
+                var leafIcon = document.createElement('span');
+                leafIcon.className = 'tree-leaf-icon';
+                leafIcon.innerHTML = '&#8627;';
+
+                var l2Label = document.createElement('label');
+                l2Label.innerHTML = '<input type="checkbox" name="menuIds" value="' + l2.id + '" ' + l2Checked + '/> ' + escapeHtml(l2.name);
+
+                l2Div.appendChild(leafIcon);
+                l2Div.appendChild(l2Label);
+                childrenDiv.appendChild(l2Div);
+            }
+
+            tree.appendChild(nodeDiv);
+            if (hasChildren) {
+                tree.appendChild(childrenDiv);
+            }
+
+            // 点击箭头或一级节点行(非复选框)切换展开/折叠
+            (function(arrow, cDiv) {
+                arrow.addEventListener('click', function(e) {
+                    toggleNode(arrow, cDiv);
+                });
+            })(arrowSpan, childrenDiv);
+        }
+    }
+
+    /**
+     * 切换子节点展开/折叠
+     */
+    function toggleNode(arrowEl, childrenEl) {
+        if (childrenEl.classList.contains('open')) {
+            childrenEl.classList.remove('open');
+            arrowEl.classList.remove('open');
+        } else {
+            childrenEl.classList.add('open');
+            arrowEl.classList.add('open');
+        }
+    }
+
+    /**
+     * 防 XSS
+     */
+    function escapeHtml(str) {
+        return String(str)
+            .replace(/&/g, '&amp;')
+            .replace(/</g, '&lt;')
+            .replace(/>/g, '&gt;')
+            .replace(/"/g, '&quot;');
+    }
+
+    /**
+     * 供父页面 layer btn1 回调调用
+     * 收集选中的菜单ID,Ajax 保存,成功返回 true
+     */
+    function doSubmit() {
+        var dictValueId = document.getElementById('dictValueId').value;
+        var checkboxes = document.querySelectorAll("input[name='menuIds']:checked");
+        var menuIds = [];
+        for (var i = 0; i < checkboxes.length; i++) {
+            menuIds.push(checkboxes[i].value);
+        }
+
+        var success = false;
+        $.ajax({
+            url: "${ctx}/sysMenuDictRelation/save",
+            type: "POST",
+            data: { dictValueId: dictValueId, menuIds: menuIds },
+            traditional: true,
+            async: false,
+            success: function(data) {
+                if (data.success) {
+                    top.layer.msg("保存成功", {icon: 1});
+                    success = true;
+                } else {
+                    top.layer.msg(data.message || "保存失败", {icon: 2});
+                }
+            },
+            error: function() {
+                top.layer.msg("请求失败,请重试", {icon: 2});
+            }
+        });
+        return success;
+    }
+
+    // 页面加载完成后渲染树
+    $(document).ready(function() {
+        renderMenuTree();
+    });
+</script>
+</body>
+</html>

+ 196 - 0
src/main/webapp/webpage/modules/SysMenuDictRelation/sysMenuDictRelationList.jsp

@@ -0,0 +1,196 @@
+<%@ 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">
+        /**
+         * 打开修改绑定弹窗
+         * @param dictValueId 字典值ID
+         * @param dictLabel   字典标签
+         * @param dictValue   字典值
+         * @param activeTab   当前激活的 tab('agenda' 或 'notify'),保存后刷新到对应 tab
+         */
+        function openBindForm(dictValueId, dictLabel, dictValue, activeTab) {
+            var url = "${ctx}/sysMenuDictRelation/form"
+                + "?dictValueId=" + encodeURIComponent(dictValueId)
+                + "&dictLabel=" + encodeURIComponent(dictLabel)
+                + "&dictValue=" + encodeURIComponent(dictValue);
+            top.layer.open({
+                type: 2,
+                area: ['600px', '85%'],
+                title: '修改绑定菜单 - ' + dictLabel,
+                maxmin: true,
+                content: url,
+                btn: ['保存', '关闭'],
+                btn1: function(index, layero) {
+                    var iframeWin = layero.find('iframe')[0];
+                    if (iframeWin.contentWindow.doSubmit()) {
+                        top.layer.close(index);
+                        // 刷新到对应 tab
+                        setTimeout(function() {
+                            if (activeTab === 'notify') {
+                                window.location.href = "${ctx}/sysMenuDictRelation/listNotify";
+                            } else {
+                                window.location.href = "${ctx}/sysMenuDictRelation/list";
+                            }
+                        }, 300);
+                    }
+                },
+                btn2: function(index) {
+                    top.layer.close(index);
+                }
+            });
+        }
+    </script>
+</head>
+<body>
+<div class="wrapper wrapper-content">
+    <sys:message content="${message}"/>
+    <div class="layui-row">
+        <div class="full-width fl">
+            <%-- 页签 Tab --%>
+            <div class="list-form-tab contentShadow shadowLTR" id="tabDiv">
+                <ul class="list-tabs">
+                    <li class="${activeTab == 'agenda' || empty activeTab ? 'active' : ''}">
+                        <a href="${ctx}/sysMenuDictRelation/list">代办页面处理</a>
+                    </li>
+                    <li class="${activeTab == 'notify' ? 'active' : ''}">
+                        <a href="${ctx}/sysMenuDictRelation/listNotify">通知页面处理</a>
+                    </li>
+                </ul>
+            </div>
+        </div>
+
+        <%-- 代办页面处理 Tab 内容 --%>
+        <c:if test="${activeTab == 'agenda' || empty activeTab}">
+        <div class="full-width fl">
+            <div class="contentShadow layui-form contentDetails">
+                <div class="nav-btns">
+                    <span class="nav-btns-label" style="font-size:13px;color:#666;">
+                        字典类型:<b>agenda_project_notify_type</b>(代办页面类型筛选)
+                    </span>
+                    <div class="layui-btn-group" style="float:right;">
+                        <button class="layui-btn layui-btn-sm" onclick="window.location.href='${ctx}/sysMenuDictRelation/list'" title="刷新">刷新</button>
+                    </div>
+                    <div style="clear: both;"></div>
+                </div>
+                <table class="layui-table" lay-skin="line">
+                    <colgroup>
+                        <col width="60">
+                        <col width="200">
+                        <col width="150">
+                        <col>
+                        <col width="110">
+                    </colgroup>
+                    <thead>
+                    <tr>
+                        <th>序号</th>
+                        <th>字典标签</th>
+                        <th>字典值</th>
+                        <th>已绑定菜单</th>
+                        <th>操作</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <c:if test="${empty dictValueList}">
+                        <tr><td colspan="5" style="text-align:center;">暂无数据</td></tr>
+                    </c:if>
+                    <c:forEach items="${dictValueList}" var="item" varStatus="idx">
+                        <tr>
+                            <td>${idx.index + 1}</td>
+                            <td>${item.label}</td>
+                            <td>${item.value}</td>
+                            <td>
+                                <c:choose>
+                                    <c:when test="${not empty item.menuNames}">${item.menuNames}</c:when>
+                                    <c:otherwise><span style="color:#aaa;">未绑定</span></c:otherwise>
+                                </c:choose>
+                            </td>
+                            <td>
+                                <a href="javascript:void(0)"
+                                   class="layui-btn layui-btn-xs layui-bg-blue"
+                                   onclick="openBindForm('${item.id}','${item.label}','${item.value}','agenda')">
+                                    修改绑定
+                                </a>
+                            </td>
+                        </tr>
+                    </c:forEach>
+                    </tbody>
+                </table>
+            </div>
+        </div>
+        </c:if>
+
+        <%-- 通知页面处理 Tab 内容 --%>
+        <c:if test="${activeTab == 'notify'}">
+        <div class="full-width fl">
+            <div class="contentShadow layui-form contentDetails">
+                <div class="nav-btns">
+                    <span class="nav-btns-label" style="font-size:13px;color:#666;">
+                        字典类型:<b>new_project_notify_type</b>(通知页面类型筛选)
+                    </span>
+                    <div class="layui-btn-group" style="float:right;">
+                        <button class="layui-btn layui-btn-sm" onclick="window.location.href='${ctx}/sysMenuDictRelation/listNotify'" title="刷新">刷新</button>
+                    </div>
+                    <div style="clear: both;"></div>
+                </div>
+                <table class="layui-table" lay-skin="line">
+                    <colgroup>
+                        <col width="60">
+                        <col width="200">
+                        <col width="150">
+                        <col>
+                        <col width="110">
+                    </colgroup>
+                    <thead>
+                    <tr>
+                        <th>序号</th>
+                        <th>字典标签</th>
+                        <th>字典值</th>
+                        <th>已绑定菜单</th>
+                        <th>操作</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <c:if test="${empty notifyDictValueList}">
+                        <tr><td colspan="5" style="text-align:center;">暂无数据</td></tr>
+                    </c:if>
+                    <c:forEach items="${notifyDictValueList}" var="item" varStatus="idx">
+                        <tr>
+                            <td>${idx.index + 1}</td>
+                            <td>${item.label}</td>
+                            <td>${item.value}</td>
+                            <td>
+                                <c:choose>
+                                    <c:when test="${not empty item.menuNames}">${item.menuNames}</c:when>
+                                    <c:otherwise><span style="color:#aaa;">未绑定</span></c:otherwise>
+                                </c:choose>
+                            </td>
+                            <td>
+                                <a href="javascript:void(0)"
+                                   class="layui-btn layui-btn-xs layui-bg-blue"
+                                   onclick="openBindForm('${item.id}','${item.label}','${item.value}','notify')">
+                                    修改绑定
+                                </a>
+                            </td>
+                        </tr>
+                    </c:forEach>
+                    </tbody>
+                </table>
+            </div>
+        </div>
+        </c:if>
+
+    </div>
+</div>
+<script src="${ctxStatic}/layer-v2.3/layui/layui.all.js" charset="utf-8"></script>
+<script>
+    resizeListWindow1();
+    $(window).resize(function(){
+        resizeListWindow1();
+    });
+</script>
+</body>
+</html>

+ 82 - 16
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseIndex.jsp

@@ -44,17 +44,17 @@
 
         /** 新增根节点 */
         function addRootNode() {
-            openTreeDialog('新增知识库分类', '${ctx}/workKnowledgeBase/tree/form', '1000px', '800px');
+            openTreeDialog('新增知识库分类', '${ctx}/workKnowledgeBase/tree/form', '1000px', '800px', false);
         }
 
         /** 新增子节点 */
         function addChildNode(parentId) {
-            openTreeDialog('新增子节点', '${ctx}/workKnowledgeBase/tree/form?parentId=' + parentId, '1000px', '500px');
+            openTreeDialog('新增子节点', '${ctx}/workKnowledgeBase/tree/form?parentId=' + parentId, '1000px', '500px', false);
         }
 
         /** 编辑节点 */
         function editNode(nodeId) {
-            openTreeDialog('编辑节点', '${ctx}/workKnowledgeBase/tree/form?id=' + nodeId, '1000px', '500px');
+            openTreeDialog('编辑节点', '${ctx}/workKnowledgeBase/tree/form?id=' + nodeId, '1000px', '800px', true);
         }
 
         /** 删除节点 */
@@ -85,8 +85,21 @@
             });
         }
 
-        /** 打开树节点弹窗 */
-        function openTreeDialog(title, url, width, height) {
+        /** 打开树节点弹窗
+         * @param title    弹窗标题
+         * @param url      表单地址
+         * @param width    宽度
+         * @param height   高度
+         * @param isEdit   true=编辑模式(保持当前选中节点),false=新增模式(选中新节点)
+         */
+        function openTreeDialog(title, url, width, height, isEdit) {
+            // 记录弹窗打开前已有节点 id 集合(新增时用于对比内容)
+            var nodeIdsBeforeAdd = [];
+            if (!isEdit) {
+                $('#treeContainer .tree-node-item').each(function() {
+                    nodeIdsBeforeAdd.push($(this).data('id'));
+                });
+            }
             top.layer.open({
                 type: 2,
                 area: [width, height],
@@ -98,12 +111,35 @@
                 btn1: function(index, layero) {
                     var body = top.layer.getChildFrame('body', index);
                     var iframeWin = layero.find('iframe')[0];
-                    var inputForm = body.find('#inputForm');
-                    inputForm.attr('target', top.getActiveTab().attr('name'));
                     if (iframeWin.contentWindow.doSubmit(1)) {
                         setTimeout(function() {
                             top.layer.close(index);
-                            refreshTree();
+                            if (isEdit) {
+                                // 编辑模式:刷新树后恢复选中原节点
+                                var savedNodeId = currentNodeId;
+                                var savedRootId = currentRootId;
+                                refreshTree(function() {
+                                    selectNodeById(savedNodeId, savedRootId);
+                                });
+                            } else {
+                                // 新增模式:刷新树后选中新增的节点
+                                refreshTree(function() {
+                                    var newNode = null;
+                                    $('#treeContainer .tree-node-item').each(function() {
+                                        var nid = $(this).data('id');
+                                        if (nodeIdsBeforeAdd.indexOf(nid) === -1) {
+                                            newNode = $(this);
+                                            return false; // break
+                                        }
+                                    });
+                                    if (newNode) {
+                                        newNode.trigger('click');
+                                    } else {
+                                        // 未找到新节点,回退为默认选中第一个
+                                        $('#treeContainer .tree-node-item').first().trigger('click');
+                                    }
+                                });
+                            }
                         }, 300);
                     }
                 },
@@ -113,13 +149,16 @@
             });
         }
 
-        /** 刷新左侧树 */
-        function refreshTree() {
+        /** 刷新左侧树(支持刷新完成后的回调) */
+        function refreshTree(callback) {
             $.ajax({
                 url: '${ctx}/workKnowledgeBase/tree/treeData',
                 success: function(data) {
                     renderTree(data);
                     bindTreeClick();
+                    if (typeof callback === 'function') {
+                        callback();
+                    }
                 }
             });
         }
@@ -131,7 +170,9 @@
         }
 
         /** 递归构建树HTML */
-        function buildTreeHtml(nodes, parentId) {
+        function buildTreeHtml(nodes, parentId, depth) {
+            depth = depth || 0;
+            var indent = 12 + depth * 16; // 根节点 12px,每层子节点向右累加 16px
             var html = '<ul class="nav nav-stacked">';
             var hasChild = false;
             for (var i = 0; i < nodes.length; i++) {
@@ -140,7 +181,7 @@
                     hasChild = true;
                     var hasChildren = hasChildNodes(nodes, node.id);
                     html += '<li>';
-                    html += '<div class="tree-node-item" data-id="' + node.id + '" data-root-id="' + node.rootId + '">';
+                    html += '<div class="tree-node-item' + (parentId === '0' ? ' root-node' : '') + '" data-id="' + node.id + '" data-root-id="' + node.rootId + '" style="padding-left:' + indent + 'px;">';
                     if (hasChildren) {
                         html += '<i class="glyphicon glyphicon-chevron-down tree-toggle" style="cursor:pointer;margin-right:3px;font-size:10px;"></i>';
                     } else {
@@ -154,7 +195,7 @@
                     html += '</span>';
                     html += '</div>';
                     if (hasChildren) {
-                        html += buildTreeHtml(nodes, node.id);
+                        html += buildTreeHtml(nodes, node.id, depth + 1);
                     }
                     html += '</li>';
                 }
@@ -163,6 +204,22 @@
             return hasChild ? html : '';
         }
 
+        /** 根据节点id选中对应树节点并加载右侧 */
+        function selectNodeById(nodeId, rootId) {
+            var target = $('#treeContainer .tree-node-item[data-id="' + nodeId + '"]');
+            if (target.length > 0) {
+                target.trigger('click');
+            } else if (rootId) {
+                // 节点可能被删除,尝试选中根节点
+                var rootTarget = $('#treeContainer .tree-node-item[data-root-id="' + rootId + '"]').first();
+                if (rootTarget.length > 0) {
+                    rootTarget.trigger('click');
+                } else {
+                    $('#treeContainer .tree-node-item').first().trigger('click');
+                }
+            }
+        }
+
         function hasChildNodes(nodes, parentId) {
             for (var i = 0; i < nodes.length; i++) {
                 if (nodes[i].parentId === parentId) return true;
@@ -213,7 +270,7 @@
         }
         .kb-left #treeContainer ul { list-style: none; padding: 0; margin: 0; }
         .kb-left .tree-node-item {
-            padding: 7px 12px;
+            padding: 7px 12px 7px 12px;
             cursor: pointer;
             font-size: 13px;
             color: #333;
@@ -224,12 +281,14 @@
         }
         .kb-left .tree-node-item:hover { background: #edf4fc; }
         .kb-left .tree-node-item.active { background: #d0e8ff; color: #1a6eb5; font-weight: bold; }
+        .kb-left .tree-node-item.root-node { font-weight: bold; }
+        .kb-left .tree-node-item.root-node.active { font-weight: bold; }
         .kb-left .tree-node-item .tree-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
         .kb-left .tree-node-item .tree-ops { opacity: 0; transition: opacity .2s; margin-left: 4px; }
         .kb-left .tree-node-item:hover .tree-ops { opacity: 1; }
         .kb-left .tree-node-item .tree-ops a { color: #888; font-size: 12px; }
         .kb-left .tree-node-item .tree-ops a:hover { color: #e94949; }
-        .kb-left li ul { padding-left: 16px; }
+        .kb-left li ul { padding-left: 0; }
         .kb-right { flex: 1; overflow: hidden; }
         .kb-right iframe { width: 100%; border: none; display: block; }
     </style>
@@ -242,7 +301,9 @@
         <div class="kb-left" id="leftPanel">
             <div class="left-header">
                 <span><i class="glyphicon glyphicon-book" style="margin-right:5px;"></i>知识库分类</span>
-                <button class="btn-add-root" onclick="addRootNode()"><i class="glyphicon glyphicon-plus"></i> 新增分类</button>
+                <shiro:hasPermission name="workKnowledgeBase:tree:add">
+                    <button class="btn-add-root" onclick="addRootNode()"><i class="glyphicon glyphicon-plus"></i> 新增分类</button>
+                </shiro:hasPermission>
             </div>
             <div id="treeContainer">
                 <script>
@@ -251,6 +312,11 @@
                     $(document).ready(function() {
                         renderTree(initTreeData);
                         bindTreeClick();
+                        // 页面初始化时自动选中第一个根节点并加载右侧列表
+                        var firstRoot = $('#treeContainer .tree-node-item').first();
+                        if (firstRoot.length > 0) {
+                            firstRoot.trigger('click');
+                        }
                     });
                 </script>
             </div>

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

@@ -0,0 +1,127 @@
+<%@ 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"/>
+    <style>
+        .detail-label { font-weight: bold; color: #555; }
+        .detail-value { color: #333; word-break: break-all; }
+    </style>
+</head>
+<body>
+<div class="single-form">
+    <div class="container">
+        <sys:message content="${message}"/>
+
+        <div class="form-group layui-row">
+            <div class="form-group-label"><h2>知识库文件信息</h2></div>
+
+            <!-- 文件名称 -->
+            <div class="layui-item layui-col-sm6 lw6">
+                <label class="layui-form-label detail-label">文件名称:</label>
+                <div class="layui-input-block">
+                    <input type="text" class="form-control layui-input" value="${entity.name}" readonly="readonly"/>
+                </div>
+            </div>
+        </div>
+
+        <!-- 动态扩展字段(只读展示) -->
+        <c:if test="${not empty dynamicFields}">
+            <div class="form-group layui-row">
+                <c:forEach items="${dynamicFields}" var="field">
+                    <div class="layui-item layui-col-sm6 lw6">
+                        <c:choose>
+                            <c:when test="${fn:length(field.fieldLabel) > 5}">
+                                <label class="layui-form-label double-line detail-label">${field.fieldLabel}:</label>
+                            </c:when>
+                            <c:otherwise>
+                                <label class="layui-form-label detail-label">${field.fieldLabel}:</label>
+                            </c:otherwise>
+                        </c:choose>
+                        <div class="layui-input-block">
+                            <c:choose>
+                                <c:when test="${field.fieldType == 'Boolean'}">
+                                    <input type="text" class="form-control layui-input" readonly="readonly"
+                                           value="${dynValues[field.id] == 'true' ? '是' : (dynValues[field.id] == 'false' ? '否' : '')}"/>
+                                </c:when>
+                                <c:otherwise>
+                                    <input type="text" class="form-control layui-input" readonly="readonly"
+                                           value="${dynValues[field.id]}"/>
+                                </c:otherwise>
+                            </c:choose>
+                        </div>
+                    </div>
+                </c:forEach>
+            </div>
+        </c:if>
+
+        <!-- 备注 -->
+        <div class="layui-item layui-col-sm12 lw6">
+            <label class="layui-form-label detail-label">备注:</label>
+            <div class="layui-input-block">
+                <textarea class="layui-textarea" readonly="readonly" rows="4">${entity.remarks}</textarea>
+            </div>
+        </div>
+
+        <!-- 附件展示 -->
+        <c:if test="${not empty entity.workAttachments}">
+            <div class="form-group layui-row">
+                <div class="form-group-label"><h2>附件信息</h2></div>
+                <div class="layui-item layui-col-xs12" style="padding:0 16px;">
+                    <table class="table table-bordered table-condensed details">
+                        <thead>
+                        <tr>
+                            <th>文件预览</th>
+                            <th>上传人</th>
+                            <th>上传时间</th>
+                            <th>文件大小(MB)</th>
+                            <th>操作</th>
+                        </tr>
+                        </thead>
+                        <tbody>
+                        <c:forEach items="${entity.workAttachments}" var="attach">
+                            <tr>
+                                <td>
+                                    <c:choose>
+                                        <c:when test="${fn:containsIgnoreCase(attach.attachmentName,'jpg')
+                                                       or fn:containsIgnoreCase(attach.attachmentName,'png')
+                                                       or fn:containsIgnoreCase(attach.attachmentName,'gif')
+                                                       or fn:containsIgnoreCase(attach.attachmentName,'jpeg')}">
+                                            <img src="${attach.temporaryUrl}" width="50" height="50"
+                                                 onclick="openPreview('${attach.temporaryUrl}',5)"
+                                                 alt="${attach.attachmentName}"/>
+                                        </c:when>
+                                        <c:when test="${fn:containsIgnoreCase(attach.attachmentName,'pdf')}">
+                                            <a class="attention-info" href="javascript:void(0)"
+                                               onclick="openPreview('${attach.temporaryUrl}',1)">${attach.attachmentName}</a>
+                                        </c:when>
+                                        <c:otherwise>
+                                            <a class="attention-info" href="javascript:void(0)"
+                                               onclick="openPreview('${attach.temporaryUrl}',2)">${attach.attachmentName}</a>
+                                        </c:otherwise>
+                                    </c:choose>
+                                </td>
+                                <td>${attach.createBy.name}</td>
+                                <td><fmt:formatDate value="${attach.createDate}" type="both"/></td>
+                                <td>${attach.fileSize}</td>
+                                <td>
+                                    <a href="${attach.temporaryUrl}" class="op-btn op-btn-download">
+                                        <i class="fa fa-download"></i>&nbsp;下载
+                                    </a>
+                                </td>
+                            </tr>
+                        </c:forEach>
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+        </c:if>
+
+        <div class="form-group layui-row page-end"></div>
+    </div>
+</div>
+</body>
+</html>

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

@@ -13,6 +13,8 @@
             if (validateForm.form()) {
                 // 提交前收集动态字段值为JSON
                 collectDynamicValues();
+                // 设置 target 为 _self,让 redirect 结果只在弹窗 iframe 内加载,不影响父页面
+                $('#inputForm').attr('target', '_self');
                 $('#inputForm').submit();
                 return true;
             }
@@ -31,7 +33,22 @@
                     error.insertAfter(element);
                 }
             });
-        });
+
+            // 初始化动态字段中 Date 类型的 laydate 日期选择器
+            layui.use('laydate', function() {
+                var laydate = layui.laydate;
+                $('input.layer-date').each(function() {
+                    laydate.render({
+                        elem: this,
+                        event: 'focus',
+                        type: 'date',
+                        format: 'yyyy-MM-dd',
+                        trigger: 'click'
+                    });
+                });
+            });
+
+            });
 
         /** 收集动态字段值为JSON数组,写入隐藏域 */
         function collectDynamicValues() {
@@ -45,20 +62,7 @@
             $('#dynamicValuesJson').val(JSON.stringify(values));
         }
 
-        /** 文件上传回调:attachmentManager 选择文件后触发上传 */
-        function insertTitle(tValue) {
-            var files = $('#attachment_file_knowledgeFile')[0].files;
-            for (var i = 0; i < files.length; i++) {
-                var file = files[i];
-                var attachmentId = '';
-                var attachmentFlag = '6';
-                var storeAs = 'workKnowledgeBaseShareInfo';
-                var uploadPath = 'http://gangwan-app.oss-cn-hangzhou.aliyuncs.com/' + storeAs;
-                var divId = '_attachment';
-                $('#addFile' + divId).show();
-                multipartUploadWithSts(storeAs, file, attachmentId, attachmentFlag, uploadPath, divId, 0);
-            }
-        }
+
     </script>
 </head>
 <body>
@@ -79,40 +83,28 @@
 
                 <!-- 文件名(必填) -->
                 <div class="layui-item layui-col-sm6 lw6">
-                    <label class="layui-form-label"><span class="require-item">*</span>文件名:</label>
+                    <label class="layui-form-label"><span class="require-item">*</span>文件名:</label>
                     <div class="layui-input-block">
-                        <form:input path="fileName" placeholder="请输入文件名称" htmlEscape="false"
+                        <form:input path="name" placeholder="请输入文件名称" htmlEscape="false"
                                     maxlength="200" class="form-control layui-input required"/>
                     </div>
                 </div>
-
-                <!-- 备注 -->
-                <div class="layui-item layui-col-sm6 lw6">
-                    <label class="layui-form-label">备注:</label>
-                    <div class="layui-input-block">
-                        <form:textarea path="remarks" placeholder="备注信息" rows="2"
-                                       class="form-control layui-input"/>
-                    </div>
-                </div>
             </div>
 
-            <!-- 文件上传区域(阿里云通用附件组件) -->
-            <table:attachmentManager
-                    title="附件上传"
-                    addBtnText="上传文件"
-                    baseId="knowledgeFile"
-                    attachments="${entity.attachments}"
-                    fileHandlerFuncName="insertTitle"
-                    attachmentFlag="199"
-                    storeAs="workKnowledgeBaseShareInfo"
-            />
-
             <!-- 动态扩展字段(与主表单整合,流式排列) -->
             <c:if test="${not empty dynamicFields}">
                 <div class="form-group layui-row">
                     <c:forEach items="${dynamicFields}" var="field">
                         <div class="layui-item layui-col-sm6 lw6">
-                            <label class="layui-form-label">${field.fieldLabel}:</label>
+                            <%-- label长度超过5个字符时使用 double-line 样式 --%>
+                            <c:choose>
+                                <c:when test="${fn:length(field.fieldLabel) > 5}">
+                                    <label class="layui-form-label double-line">${field.fieldLabel}:</label>
+                                </c:when>
+                                <c:otherwise>
+                                    <label class="layui-form-label">${field.fieldLabel}:</label>
+                                </c:otherwise>
+                            </c:choose>
                             <div class="layui-input-block">
                                 <c:choose>
                                     <c:when test="${field.fieldType == 'Integer'}">
@@ -123,6 +115,14 @@
                                                placeholder="请输入整数"
                                                value="${dynValues[field.id]}"/>
                                     </c:when>
+                                    <c:when test="${field.fieldType == 'Long'}">
+                                        <input type="text"
+                                               class="form-control layui-input dynamic-field-input digits"
+                                               data-field-id="${field.id}"
+                                               data-field-key="${field.fieldKey}"
+                                               placeholder="请输入整数"
+                                               value="${dynValues[field.id]}"/>
+                                    </c:when>
                                     <c:when test="${field.fieldType == 'Double'}">
                                         <input type="text"
                                                class="form-control layui-input dynamic-field-input number"
@@ -131,6 +131,37 @@
                                                placeholder="请输入小数"
                                                value="${dynValues[field.id]}"/>
                                     </c:when>
+                                    <c:when test="${field.fieldType == 'BigDecimal'}">
+                                        <input type="text"
+                                               class="form-control layui-input dynamic-field-input number"
+                                               data-field-id="${field.id}"
+                                               data-field-key="${field.fieldKey}"
+                                               placeholder="请输入数字"
+                                               value="${dynValues[field.id]}"/>
+                                    </c:when>
+                                    <c:when test="${field.fieldType == 'Boolean'}">
+                                        <select class="form-control layui-input dynamic-field-input"
+                                                data-field-id="${field.id}"
+                                                data-field-key="${field.fieldKey}">
+                                            <option value=""
+                                                <c:if test="${empty dynValues[field.id]}">selected</c:if>>请选择</option>
+                                            <option value="true"
+                                                <c:if test="${dynValues[field.id] == 'true'}">selected</c:if>>是</option>
+                                            <option value="false"
+                                                <c:if test="${dynValues[field.id] == 'false'}">selected</c:if>>否</option>
+                                        </select>
+                                    </c:when>
+                                    <c:when test="${field.fieldType == 'Date'}">
+                                        <input type="text"
+                                               style="background-color: #FFF"
+                                               id="dynDate_${field.id}"
+                                               class="form-control layui-input dynamic-field-input laydate-icondate layer-date layui-input laydate-icon"
+                                               data-field-id="${field.id}"
+                                               data-field-key="${field.fieldKey}"
+                                               placeholder="请选择日期"
+                                               value="${dynValues[field.id]}"
+                                               readonly="readonly"/>
+                                    </c:when>
                                     <c:otherwise>
                                         <input type="text"
                                                class="form-control layui-input dynamic-field-input"
@@ -146,6 +177,28 @@
                 </div>
             </c:if>
 
+
+
+            <!-- 备注 -->
+            <div class="layui-form-item layui-col-sm12 lw6">
+                <label class="layui-form-label">备注:</label>
+                <div class="layui-input-block">
+                    <form:textarea path="remarks" placeholder="备注信息" rows="4" maxlength="200" class="layui-textarea"></form:textarea>
+                </div>
+            </div>
+
+
+
+            <!-- 文件上传区域(单文件上传,最多1个) -->
+            <table:singleAttachmentManager
+                    title="附件上传"
+                    addBtnText="上传文件"
+                    baseId="knowledgeFile"
+                    attachments="${entity.workAttachments}"
+                    attachmentFlag="199"
+                    storeAs="workKnowledgeBaseShareInfo"
+            />
+
             <div class="form-group layui-row page-end"></div>
         </form:form>
     </div>

+ 123 - 27
src/main/webapp/webpage/modules/WorkKnowledgeBase/workKnowledgeBaseShareList.jsp

@@ -10,7 +10,36 @@
         var currentRootId = '${rootId}';
 
         $(document).ready(function() {
-            // do nothing, layui table rendered below
+            // moresee 展开/收起动态字段查询区
+            $('#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');
+                }
+                return false;
+            });
+
+            // 初始化创建时间 laydate 日期选择器
+            layui.use('laydate', function() {
+                var laydate = layui.laydate;
+                laydate.render({
+                    elem: '#beginDate',
+                    event: 'focus',
+                    type: 'date',
+                    format: 'yyyy-MM-dd',
+                    trigger: 'click'
+                });
+                laydate.render({
+                    elem: '#endDate',
+                    event: 'focus',
+                    type: 'date',
+                    format: 'yyyy-MM-dd',
+                    trigger: 'click'
+                });
+            });
         });
 
         function openDialog(title, url, width, height, target) {
@@ -29,16 +58,33 @@
                     var body = top.layer.getChildFrame('body', index);
                     var iframeWin = layero.find('iframe')[0];
                     var inputForm = body.find('#inputForm');
-                    var top_iframe = top.getActiveTab().attr('name');
-                    inputForm.attr('target', top_iframe);
+                    // redirect 结果只在弹窗 iframe 内加载,不影响父页面
+                    inputForm.attr('target', '_self');
                     if (iframeWin.contentWindow.doSubmit(1)) {
-                        setTimeout(function() { top.layer.close(index); }, 100);
+                        setTimeout(function() {
+                            top.layer.close(index);
+                            // 弹窗关闭后刷新右侧列表
+                            search();
+                        }, 300);
                     }
                 },
                 btn2: function(index) { layer.close(index); }
             });
         }
 
+        /** 查看详情 */
+        function openDetailDialog(id) {
+            top.layer.open({
+                type: 2,
+                area: ['80%', '80%'],
+                title: '文件详情',
+                maxmin: true,
+                content: '${ctx}/workKnowledgeBase/share/detail?id=' + id + '&treeNodeId=${treeNodeId}&rootId=${rootId}',
+                btn: ['关闭'],
+                btn1: function(index) { top.layer.close(index); }
+            });
+        }
+
         /** 删除文件 */
         function deleteShare(id) {
             layer.open({
@@ -72,7 +118,6 @@
 
         /** 重置查询 */
         function resetSearch() {
-            // 清空所有查询输入
             $('#searchForm input[type=text]').val('');
             $('#searchForm input[type=search]').val('');
             $('#searchForm').submit();
@@ -100,19 +145,51 @@
                     <input type="hidden" name="rootId" value="${rootId}"/>
                     <input id="pageNo" name="pageNo" type="hidden" value="${page.pageNo}"/>
                     <input id="pageSize" name="pageSize" type="hidden" value="${page.pageSize}"/>
-                    <div class="commonQuery">
-                        <%-- 固定查询:文件名 --%>
+                    <div class="commonQuery lw7">
+                        <%-- 第一行:固定查询(文件名 + 创建时间区间 + 查询按钮) --%>
                         <div class="layui-item query athird">
-                            <label class="layui-form-label">文件名:</label>
+                            <label class="layui-form-label">文件名:</label>
                             <div class="layui-input-block with-icon">
-                                <input type="text" name="fileName" value="${shareInfo.fileName}"
-                                       placeholder="文件名模糊查询" class="form-control layui-input"/>
+                                <input type="text" name="name" value="${shareInfo.name}"
+                                       placeholder="文件名称模糊查询" class="form-control layui-input"/>
+                            </div>
+                        </div>
+                        <div class="layui-item query athird">
+                            <label class="layui-form-label">创建时间:</label>
+                            <div class="layui-input-block readOnlyFFF with-icon">
+                                <input id="beginDate" placeholder="开始时间" name="beginDate" type="text" readonly="readonly"
+                                       maxlength="20" class="laydate-icondate form-control layer-date layui-input laydate-icon query-group"
+                                       value="${shareInfo.beginDate}"/>
+                                <span class="group-sep">-</span>
+                                <input id="endDate" placeholder="结束时间" name="endDate" type="text" readonly="readonly"
+                                       maxlength="20" class="laydate-icondate form-control layer-date layui-input laydate-icon query-group"
+                                       value="${shareInfo.endDate}"/>
+                            </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>
-                        <%-- 动态查询项:根据表3配置自动生成 --%>
+                        <div style="clear:both;"></div>
+                    </div>
+
+                    <%-- 展开区域:动态字段查询(默认隐藏) --%>
+                    <div id="moresees" style="clear:both;display:none;" class="lw7">
                         <c:forEach items="${dynamicFields}" var="field">
                             <div class="layui-item query athird">
-                                <label class="layui-form-label">${field.fieldLabel}:</label>
+                                <c:choose>
+                                    <c:when test="${fn:length(field.fieldLabel) > 5}">
+                                        <label class="layui-form-label" style="line-height:20px">${field.fieldLabel}:</label>
+                                    </c:when>
+                                    <c:otherwise>
+                                        <label class="layui-form-label">${field.fieldLabel}:</label>
+                                    </c:otherwise>
+                                </c:choose>
                                 <div class="layui-input-block with-icon">
                                     <input type="text" name="dynamic_${field.id}"
                                            value="${dynamicConditions[field.id]}"
@@ -121,14 +198,6 @@
                                 </div>
                             </div>
                         </c:forEach>
-                        <div class="layui-item athird">
-                            <div class="input-group">
-                                <div class="layui-btn-group search-spacing">
-                                    <button type="button" class="layui-btn layui-btn-sm layui-bg-blue" onclick="search()">查询</button>
-                                    <button type="button" class="layui-btn layui-btn-sm" onclick="resetSearch()">重置</button>
-                                </div>
-                            </div>
-                        </div>
                         <div style="clear:both;"></div>
                     </div>
                 </form>
@@ -181,13 +250,27 @@
         // 构建动态列配置
         var cols = [
             {field: 'index', align: 'center', width: 50, title: '序号'},
-            {field: 'fileName', align: 'center', title: '文件名', minWidth: 150},
+            {field: 'name', align: 'center', title: '文件名称', minWidth: 150, templet: function(d) {
+                return '<a href="javascript:void(0)" class="attention-info" onclick="openDetailDialog(\'' + d.id + '\')">' + (d.name || '') + '</a>';
+            }},
             {field: 'fileUrl', align: 'center', title: '文件地址', minWidth: 200, templet: function(d) {
-                if (d.fileUrl && d.fileUrl !== '') {
-                    return '<a href="' + d.fileUrl + '" target="_blank" title="' + d.fileUrl + '">' +
-                           '<i class="glyphicon glyphicon-paperclip"></i> 查看文件</a>';
+                if(2 == d.uploadMode){
+                    if(d.fileName.toLowerCase().indexOf('jpg') != -1 || d.fileName.toLowerCase().indexOf('png') != -1 || d.fileName.toLowerCase().indexOf('gif') != -1 || d.fileName.toLowerCase().indexOf('bmp') != -1 || d.fileName.toLowerCase().indexOf('jpeg') != -1){
+                        return "<img src="+d.temporaryUrl+" width='50' height='50' onclick=\"openDialogView('预览','${ctx}/sys/picturepreview/picturePreview?url=" + d.temporaryUrl +"','90%','90%')\" alt='"+d.fileName+"'>";
+                    }else if(d.fileName.toLowerCase().indexOf('pdf') != -1){
+                        return "<a class=\"attention-info\" title=\"" + d.fileName + "\" href=\"javascript:void(0);\" onclick=\"openPreview('" + d.temporaryUrl +"',1)\">" + d.fileName + "</a>";
+                    }else{
+                        return "<a class=\"attention-info\" title=\"" + d.fileName + "\" href=\"javascript:void(0);\" onclick=\"openPreview('" + d.temporaryUrl +"',2)\">" + d.fileName + "</a>";
+                    }
+                }else{
+                    if(d.fileName.toLowerCase().indexOf('jpg') != -1 || d.fileName.toLowerCase().indexOf('png') != -1 || d.fileName.toLowerCase().indexOf('gif') != -1 || d.fileName.toLowerCase().indexOf('bmp') != -1 || d.fileName.toLowerCase().indexOf('jpeg') != -1){
+                        return "<img src="+d.fileUrl+" width='50' height='50' onclick=\"openDialogView('预览','${ctx}/sys/picturepreview/picturePreview?url=" + d.fileUrl +"','90%','90%')\" alt='"+d.fileName+"'>";
+                    }else if(d.fileName.toLowerCase().indexOf('pdf') != -1){
+                        return "<a class=\"attention-info\" title=\"" + d.fileName + "\" href=\"javascript:void(0);\" onclick=\"openPreview('" + d.fileUrl +"',1)\">" + d.fileName + "</a>";
+                    }else{
+                        return "<a class=\"attention-info\" title=\"" + d.fileName + "\" href=\"javascript:void(0);\" onclick=\"openPreview('" + d.fileUrl +"',2)\">" + d.fileName + "</a>";
+                    }
                 }
-                return '-';
             }},
             <c:forEach items="${dynamicFields}" var="field">
             {field: 'dynamic_${field.fieldKey}', align: 'center', title: '${field.fieldLabel}', minWidth: 100},
@@ -195,8 +278,12 @@
             {field: 'createTime', align: 'center', title: '创建时间', width: 160},
             {align: 'center', title: '操作', width: 160, fixed: 'right', templet: function(d) {
                 var xml = '<div class="layui-btn-group">';
-                xml += '<a href="javascript:void(0)" onclick="openDialog(\'编辑文件\',\'${ctx}/workKnowledgeBase/share/form?id=' + d.id + '&treeNodeId=${treeNodeId}&rootId=${rootId}\',\'80%\',\'80%\')" class="layui-btn layui-btn-xs layui-bg-green"> 修改</a>';
-                xml += '<a href="javascript:void(0)" onclick="deleteShare(\'' + d.id + '\')" class="layui-btn layui-btn-xs layui-bg-red"> 删除</a>';
+                    if(d.canedit != undefined && d.canedit == "1"){
+                        xml += '<a href="javascript:void(0)" onclick="openDialog(\'编辑文件\',\'${ctx}/workKnowledgeBase/share/form?id=' + d.id + '&treeNodeId=${treeNodeId}&rootId=${rootId}\',\'80%\',\'80%\')" class="layui-btn layui-btn-xs layui-bg-green"> 修改</a>';
+                    }
+                    if(d.candelete != undefined && d.candelete == "1"){
+                        xml += '<a href="javascript:void(0)" onclick="deleteShare(\'' + d.id + '\')" class="layui-btn layui-btn-xs layui-bg-red"> 删除</a>';
+                    }
                 xml += '</div>';
                 return xml;
             }}
@@ -216,11 +303,20 @@
                 {
                     "index": "${status.index + 1}"
                     ,"id": "${row.id}"
+                    ,"name": "<c:out value='${row.name}'/>"
                     ,"fileName": "<c:out value='${row.fileName}'/>"
+                    ,"attachmentName": "<c:out value='${row.attachmentName}'/>"
+                    ,"temporaryUrl": "<c:out value='${row.temporaryUrl}'/>"
+                    ,"uploadMode": "<c:out value='${row.uploadMode}'/>"
                     ,"fileUrl": "<c:out value='${row.fileUrl}'/>"
                     ,"createTime": "${row.createTime}"
                     <c:forEach items="${dynamicFields}" var="field">
                     ,"dynamic_${field.fieldKey}": "<c:out value='${row["dynamic_".concat(field.fieldKey)]}'/>"
+
+                    <c:if test="${fns:getUser().id == row.createBy.id}">
+                    <shiro:hasPermission name="workKnowledgeBase:share:edit">,"canedit":"1"</shiro:hasPermission>
+                    <shiro:hasPermission name="workKnowledgeBase:share:del">,"candelete":"1"</shiro:hasPermission>
+                    </c:if>
                     </c:forEach>
                 }
                 </c:forEach>

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

@@ -18,6 +18,8 @@
         function doSubmit(i) {
             if (validateForm.form()) {
                 collectDynamicFields();
+                // 设置 target 为 _self,让 redirect 结果只在弹窗 iframe 内加载,不影响父页面
+                $('#inputForm').attr('target', '_self');
                 $('#inputForm').submit();
                 return true;
             }
@@ -65,6 +67,10 @@
             var selectedString = (fieldType === 'String') ? 'selected' : '';
             var selectedInteger = (fieldType === 'Integer') ? 'selected' : '';
             var selectedDouble = (fieldType === 'Double') ? 'selected' : '';
+            var selectedLong = (fieldType === 'Long') ? 'selected' : '';
+            var selectedBigDecimal = (fieldType === 'BigDecimal') ? 'selected' : '';
+            var selectedBoolean = (fieldType === 'Boolean') ? 'selected' : '';
+            var selectedDate = (fieldType === 'Date') ? 'selected' : '';
 
             var tr = '<tr id="dynRow_' + idx + '">'
                 + '<td><input type="hidden" name="dynId_' + idx + '" value="' + id + '"/>'
@@ -74,6 +80,11 @@
                 + '<option value="String" ' + selectedString + '>String</option>'
                 + '<option value="Integer" ' + selectedInteger + '>Integer</option>'
                 + '<option value="Double" ' + selectedDouble + '>Double</option>'
+                + '<option value="Long" ' + selectedLong + '>Long</option>'
+                + '<option value="BigDecimal" ' + selectedBigDecimal + '>BigDecimal</option>'
+                + '<option value="Boolean" ' + selectedBoolean + '>Boolean</option>'
+                + '<option value="Date" ' + selectedDate + '>Date</option>'
+
                 + '</select></td>'
                 + '<td><input type="number" name="dynSort_' + idx + '" value="' + sort + '" placeholder="排序" class="layui-input" style="width:100%;"/></td>'
                 + '<td><a href="javascript:void(0)" onclick="removeDynRow(' + idx + ')" class="layui-btn layui-btn-xs layui-btn-danger">删除</a></td>'

+ 269 - 0
src/main/webapp/webpage/modules/WorkOssNoteInformInfo/workOssNoteInformInfoList.jsp

@@ -0,0 +1,269 @@
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@ page isELIgnored="false"%>
+<%@ include file="/webpage/include/taglib.jsp"%>
+<html>
+<head>
+    <title>阿里云短信记录管理</title>
+    <meta name="decorator" content="default"/>
+    <style>
+        .layui-layer-btn1:hover{
+            color: #c2c2c2;
+        }
+    </style>
+    <script type="text/javascript">
+        $(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: '#sendTimeStart', //目标元素。由于laydate.js封装了一个轻量级的选择器引擎,因此elem还允许你传入class、tag但必须按照这种方式 '#id .class'
+                event: 'focus', //响应事件。如果没有传入event,则按照默认的click
+                type : 'date'
+                , trigger: 'click'
+            });
+            laydate.render({
+                elem: '#sendTimeEnd', //目标元素。由于laydate.js封装了一个轻量级的选择器引擎,因此elem还允许你传入class、tag但必须按照这种方式 '#id .class'
+                event: 'focus', //响应事件。如果没有传入event,则按照默认的click
+                type : 'date'
+                , trigger: 'click'
+            });
+        });
+        function switchInput(obj){
+            $("#"+obj).show();
+            $("#"+obj).siblings().hide();
+        }
+        //打开对话框(查看)
+        function openDialogNow(title,url,width,height){
+            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: ['关闭'],
+                cancel: function(index){
+                }
+            });
+        }
+
+        function cBlur(obj) {
+            var id = $("#receiveUserId").val();
+            if(undefined != obj.value && null != obj.value && '' != obj.value){
+                $.ajax({
+                    url:'${ctx}/sys/user/getUserByName?name='+obj.value,
+                    type:"post",
+                    success:function(data){
+                        var user = data.body.data;
+                        if(undefined == user || null == user || '' == user){
+                            $("#receiveUserId").val("");
+                        }else{
+                            if(data.body.data.id != id){
+                                if(undefined != id && null != id && '' != id){
+                                    $("#receiveUserId").val("");
+                                }
+                            }
+                        }
+                    }
+                });
+            }else{
+                $("#accountCheckingUserId").val("");
+            }
+
+        }
+
+
+
+    </script>
+</head>
+<body class="gray-bg">
+<div class="wrapper wrapper-content">
+    <sys:message content="${message}"/>
+    <div class="layui-row">
+        <div class="full-width fl">
+            <div class="layui-row contentShadow shadowLR" id="queryDiv">
+                <form:form id="searchForm" modelAttribute="workOssNoteInformInfo" action="${ctx}/workOssNoteInformInfo/list" method="post" class="form-inline">
+                    <input id="pageNo" name="pageNo" type="hidden" value="${page.pageNo}"/>
+                    <input id="pageSize" name="pageSize" type="hidden" value="${page.pageSize}"/>
+                    <input id="toflag" name="toflag" type="hidden" value="1"/>
+                    <%--<table:sortColumn id="orderBy" name="orderBy" value="${page.orderBy}" callback="sortOrRefresh();"/><!-- 支持排序 -->--%>
+                    <div class="commonQuery lw7">
+                        <div class="layui-item query athird">
+                            <label class="layui-form-label">短信接收人:</label>
+                            <div class="layui-input-block  with-icon">
+                                <sys:inquireselectUserNotReadolny id="receiveUser" name="receiveUserId" value="${workOssNoteInformInfo.receiveUserId}" labelName="receiveUserName" labelValue="${workOssNoteInformInfo.receiveUserName}"
+                                                                  title="用户" url="/sys/office/treeDataAll?type=3" cssClass="form-control required layui-input" allowClear="true" notAllowSelectParent="true"/>
+                            </div>
+                        </div>
+
+                        <div class="layui-item query athird">
+                            <label class="layui-form-label"  style="line-height:20px">接收手机号:</label>
+                            <div class="layui-input-block">
+                                <form:input path="phone" htmlEscape="false"  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>
+                                    <%--								<a href="#" id="moresee"><i class="glyphicon glyphicon-menu-down"></i></a>--%>
+                                    <%--								<button id="searchReset" class="fixed-btn searchReset fr" onclick="resetSearch()">重置</button>--%>
+                                    <%--								<button id="searchQuery" class="fixed-btn searchQuery fr" onclick="search()">查询</button>--%>
+                            </div>
+                        </div>
+                        <div style="    clear:both;"></div>
+                    </div>
+                    <div id="moresees" style="clear:both;display:none;" class="lw7">
+
+                        <div class="layui-item query athird">
+                            <label class="layui-form-label"  style="line-height:20px">短信内容:</label>
+                            <div class="layui-input-block">
+                                <form:input path="sendContent" htmlEscape="false"  class="form-control layui-input"/>
+                            </div>
+                        </div>
+
+                        <div class="layui-item query athird">
+                            <label class="layui-form-label">发送时间:</label>
+                            <div class="layui-input-block readOnlyFFF">
+                                <input id="sendTimeStart" placeholder="开始时间" name="sendTimeStart" type="text" readonly="readonly" maxlength="20" class="laydate-icondate form-control layer-date layui-input laydate-icon query-group"
+                                       value="<fmt:formatDate value="${workOssNoteInformInfo.sendTimeStart}" pattern="yyyy-MM-dd"/>"/>
+                                </input>
+                                <span class="group-sep">-</span>
+                                <input id="sendTimeEnd" placeholder="结束时间" name="sendTimeEnd" type="text" readonly="readonly" maxlength="20" class="laydate-icondate form-control layer-date layui-input laydate-icon query-group"
+                                       value="<fmt:formatDate value="${workOssNoteInformInfo.sendTimeEnd}" pattern="yyyy-MM-dd"/>"/>
+                                </input>
+                            </div>
+                        </div>
+
+                        <div class="layui-item query athird">
+                            <label class="layui-form-label"  style="line-height:20px">短信所属模块:</label>
+                            <div class="layui-input-block">
+                                <form:input path="smsModule" htmlEscape="false"  class="form-control layui-input"/>
+                            </div>
+                        </div>
+
+                        <%--<div class="layui-item query athird">
+                            <label class="layui-form-label"  style="line-height:20px">短信发送状态:</label>
+                            <div class="layui-input-block">
+                                <form:input path="statusCode" htmlEscape="false"  class="form-control layui-input"/>
+                            </div>
+                        </div>--%>
+
+                        <div class="layui-item query athird">
+                            <label class="layui-form-label"  style="line-height:20px">短信发送结果:</label>
+                            <div class="layui-input-block">
+                                <form:input path="message" htmlEscape="false"  class="form-control layui-input"/>
+                            </div>
+                        </div>
+
+                    </div>
+                </form:form>
+            </div>
+        </div>
+
+        <div class="full-width fl">
+            <div class="contentShadow layui-form contentDetails">
+                <div class="nav-btns">
+                    <%--此处按钮样式包括 nav-btn-add nav-btn-refresh nav-btn-import nav-btn-export nav-btn-query nav-btn-reset--%>
+                    <div class="layui-btn-group">
+                        <shiro:hasPermission name="workclientinfo:workClientInfo:export">
+                            <table:exportExcel url="${ctx}/workclientinfo/workClientInfo/export"></table:exportExcel><!-- 导出按钮 -->
+                        </shiro:hasPermission>
+                        <button class="layui-btn layui-btn-sm" data-toggle="tooltip" data-placement="left" onclick="sortOrRefresh()" title="刷新"> 刷新</button>
+                    </div>
+                    <div style="clear: both;"></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: [[
+                {field:'index',align:'center', title: '序号',width:40}
+                ,{field:'receiveUserName',align:'center', title: '接收人',width:120}
+                ,{field:'phone',align:'center', title: '接收手机号',width:120}
+                ,{field:'sendContent', align:'center',title: '发送内容',minWidth:200}
+                ,{field:'sendTime',align:'center', title: '发送时间', width:150}
+                /*,{field:'smsType',align:'center', title: '短信类型', width:120}*/
+                ,{field:'smsModule',align:'center', title: '短信所属模块', width:120}
+                /*,{field:'statusCode',align:'center', title: '短信发送状态', width:120}*/
+                ,{field:'message',align:'center', title: '短信发送结果', width:120}
+                /*,{field:'op',align:'center',title:"操作",width:130,templet:function(d){
+                        ////对操作进行初始化
+                        var xml = "<div class=\"layui-btn-group\">";
+
+                        if(d.canedit != undefined && d.canedit == "1")
+                            xml +="<a href=\"javascript:void(0)\" onclick=\"openDialog('修改客户信息', '${ctx}/workclientinfo/workClientInfo/form?id=" + d.id + "&param=1','95%','95%')\" class=\"layui-btn layui-btn-xs layui-bg-green\" > 修改</a>"
+
+                        if(d.candelete != undefined && d.candelete == "1")
+                            xml +="<a href=\"javascript:void(0)\" onclick=\"deleteFun('${ctx}/workclientinfo/workClientInfo/delete?id=" + d.id + "')\"   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="workOssNoteInformInfo" varStatus="index">
+                <c:if test="${index.index != 0}">,</c:if>
+                {
+                    "index":"${index.index+1}"
+                    ,"id":"${workOssNoteInformInfo.id}"
+                    ,"receiveUserName":"${workOssNoteInformInfo.receiveUserName}"
+                    ,"phone":"${workOssNoteInformInfo.phone}"
+                    ,"sendContent":"${workOssNoteInformInfo.sendContent}"
+                    ,"smsType":"${workOssNoteInformInfo.smsType}"
+                    ,"smsModule":"${workOssNoteInformInfo.smsModule}"
+                    ,"statusCode":"${workOssNoteInformInfo.statusCode}"
+                    ,"message":"${workOssNoteInformInfo.message}"
+                    ,"sendTime":"<fmt:formatDate value="${workOssNoteInformInfo.sendTime}" pattern="yyyy-MM-dd"/>"
+                }
+                </c:forEach>
+                </c:if>
+            ]
+        });
+
+    })
+
+    resizeListTable();/*消除由于有竖向滚动条造成table出现横向滚动条*/
+    $("a").on("click",addLinkVisied);
+</script>
+
+<script type="text/javascript">
+    resizeListWindow1();
+    $(window).resize(function(){
+        resizeListWindow1();
+    });
+</script>
+</body>
+
+</html>
+

+ 1 - 1
src/main/webapp/webpage/modules/ruralprojectrecords/ruralProjectRecordsList.jsp

@@ -586,7 +586,7 @@
                         if(d.deleteAdmin != undefined && d.deleteAdmin =="1")
                         {
 							xml+="<a href=\"#\" onclick=\"openDialogre('修改项目', '${ctx}/ruralProject/ruralProjectRecords/adminModify?id=" + d.id + "','95%', '95%','','提交,关闭')\" class=\"layui-btn layui-btn-xs  layui-bg-green\" > 修改</a>";
-							xml+="<a href=\"${ctx}/ruralProject/ruralProjectRecords/adminDelete?id=" + d.id + "\" onclick=\"return confirmx('确认要删除该项目信息吗?', this.href)\" class=\"layui-btn layui-btn-xs layui-bg-red\"> 删除</a>";
+							xml+="<a href=\"${ctx}/ruralProject/ruralProjectRecords/adminDeleteOnPost?id=" + d.id + "\" onclick=\"return confirmx('确认要删除该项目信息吗?', this.href)\" class=\"layui-btn layui-btn-xs layui-bg-red\"> 删除</a>";
 							 }
 						if(d.modifyRecords != undefined && d.modifyRecords =="1")
 						{

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

@@ -576,7 +576,8 @@
                     <div class="col-sm-12" style="padding: 0;">
                         <div class="ibox float-e-margins">
                             <div class="ibox-title">
-                                <h2 style="text-indent: 12px;margin-top: 10px;font-size: 16px;font-weight: bold;border-left: 5px solid #009FFA;">基本信息</h2>
+                                <h2 style="text-indent: 12px;margin-top: 10px;font-size: 16px;font-weight: bold;border-left: 5px solid #009FFA;">基本信息 <span style="color:#888888; font-size:12px; font-weight:normal;">  (基本信息修改审核人:杨娟;职业资格证修改审核人:韩丽、刘芸)</span></h2>
+
                                 <div class="ibox-tools" style="margin-top: -20px">
                                     <a style="display:block;" class="dropdown-toggle" data-toggle="dropdown"
                                        href="javascript:void(0)">

+ 19 - 4
src/main/webapp/webpage/modules/workprojectnotify/workProjectNotifyBacklogListByMine.jsp

@@ -6,6 +6,21 @@
 	<meta name="decorator" content="default"/>
 	<script type="text/javascript">
 		$(document).ready(function() {
+			// 按当前用户菜单权限动态加载类型下拉框
+			var currentTypeVal = '${workProjectNotify.types}';
+			$.ajax({
+				url: '${ctx}/sysMenuDictRelation/getDictValuesByPermission',
+				type: 'GET',
+				success: function(data) {
+					var select = $('#type');
+					select.empty().append('<option value=""></option>');
+					$.each(data, function(i, item) {
+						var selected = (item.value == currentTypeVal) ? ' selected' : '';
+						select.append('<option value="' + item.value + '"' + selected + '>' + item.label + '</option>');
+					});
+					layui.form.render('select');
+				}
+			});
 			//搜索框收放
 			$('#moresee').click(function(){
 				if($('#moresees').is(':visible'))
@@ -398,10 +413,10 @@
 					<div class="layui-item query athird">
 						<label class="layui-form-label">类型:</label>
 						<div class="layui-input-block">
-							<form:select id="type" path="types" class="form-control simple-select">
-								<form:option value="" label=""/>
-								<form:options items="${fns:getDictList('agenda_project_notify_type')}" itemLabel="label" itemValue="value" htmlEscape="false"/>
-							</form:select>
+							<!-- 类型下拉框:按当前用户菜单权限动态加载,不使用全局字典 -->
+							<select id="type" name="types" class="form-control simple-select">
+								<option value=""></option>
+							</select>
 						</div>
 					</div>
 					<div class="layui-item athird">

+ 20 - 4
src/main/webapp/webpage/modules/workprojectnotify/workProjectNotifyList.jsp

@@ -8,6 +8,22 @@
 	<script type="text/javascript">
 		$(document).ready(function() {
 
+			// 按当前用户菜单权限动态加载类型下拉框
+			var currentTypeVal = '${workProjectNotify.types}';
+			$.ajax({
+				url: '${ctx}/sysMenuDictRelation/getDictValuesByPermission',
+				type: 'GET',
+				success: function(data) {
+					var select = $('#type');
+					select.empty().append('<option value=""></option>');
+					$.each(data, function(i, item) {
+						var selected = (item.value == currentTypeVal) ? ' selected' : '';
+						select.append('<option value="' + item.value + '"' + selected + '>' + item.label + '</option>');
+					});
+					layui.form.render('select');
+				}
+			});
+
 			//搜索框收放
 			$('#moresee').click(function(){
 				if($('#moresees').is(':visible'))
@@ -656,10 +672,10 @@
 					<div class="layui-item query athird">
 						<label class="layui-form-label">类型:</label>
 						<div class="layui-input-block">
-							<form:select id="type" path="types" class="form-control simple-select">
-								<form:option value="" label=""/>
-								<form:options items="${fns:getDictList('agenda_project_notify_type')}" itemLabel="label" itemValue="value" htmlEscape="false"/>
-							</form:select>
+							<!-- 类型下拉框:按当前用户菜单权限动态加载,不使用全局字典 -->
+							<select id="type" name="types" class="form-control simple-select">
+								<option value=""></option>
+							</select>
 						</div>
 					</div>
 					<div class="layui-item athird">

+ 19 - 4
src/main/webapp/webpage/modules/workprojectnotify/workProjectNotifyReadBacklogList.jsp

@@ -6,6 +6,21 @@
 	<meta name="decorator" content="default"/>
 	<script type="text/javascript">
 		$(document).ready(function() {
+			// 按当前用户菜单权限动态加载类型下拉框
+			var currentTypeVal = '${workProjectNotify.types}';
+			$.ajax({
+				url: '${ctx}/sysMenuDictRelation/getDictValuesByPermission',
+				type: 'GET',
+				success: function(data) {
+					var select = $('#type');
+					select.empty().append('<option value=""></option>');
+					$.each(data, function(i, item) {
+						var selected = (item.value == currentTypeVal) ? ' selected' : '';
+						select.append('<option value="' + item.value + '"' + selected + '>' + item.label + '</option>');
+					});
+					layui.form.render('select');
+				}
+			});
 			//搜索框收放
 			$('#moresee').click(function(){
 				if($('#moresees').is(':visible'))
@@ -419,10 +434,10 @@
 					<div class="layui-item query athird">
 						<label class="layui-form-label">类型:</label>
 						<div class="layui-input-block">
-							<form:select id="type" path="types" class="form-control simple-select">
-								<form:option value="" label=""/>
-								<form:options items="${fns:getDictList('agenda_project_notify_type')}" itemLabel="label" itemValue="value" htmlEscape="false"/>
-							</form:select>
+							<!-- 类型下拉框:按当前用户菜单权限动态加载,不使用全局字典 -->
+							<select id="type" name="types" class="form-control simple-select">
+								<option value=""></option>
+							</select>
 						</div>
 					</div>
 					<div class="layui-item athird">

+ 18 - 4
src/main/webapp/webpage/modules/workprojectnotify/workProjectNotifyReadShowList.jsp

@@ -7,6 +7,21 @@
 	<meta name="decorator" content="default"/>
 	<script type="text/javascript">
 		$(document).ready(function() {
+			// 按权限加载通知页面类型下拉框
+			var currentTypeVal = '${workProjectNotify.types}';
+			$.ajax({
+				url: '${ctx}/sysMenuDictRelation/getNotifyDictValuesByPermission',
+				type: 'GET',
+				success: function(data) {
+					var select = $('#types');
+					select.empty().append('<option value=""></option>');
+					$.each(data, function(i, item) {
+						var selected = (item.value == currentTypeVal) ? ' selected' : '';
+						select.append('<option value="' + item.value + '"' + selected + '>' + item.label + '</option>');
+					});
+					layui.form.render('select');
+				}
+			});
 		});
         function openDialogre(title,url,width,height,target){
             if(navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)){//如果是移动端,就使用自适应大小弹窗
@@ -154,10 +169,9 @@
 						<div class="layui-item query athird">
 							<label class="layui-form-label">类型:</label>
 							<div class="layui-input-block">
-								<form:select id="types" path="types" class="form-control simple-select">
-									<form:option value="" label=""/>
-									<form:options items="${fns:getDictList('new_project_notify_type')}" itemLabel="label" itemValue="value" htmlEscape="false"/>
-								</form:select>
+								<select id="types" name="types" class="form-control simple-select">
+									<option value=""></option>
+								</select>
 							</div>
 						</div>
 						<div class="layui-item athird">

+ 18 - 4
src/main/webapp/webpage/modules/workprojectnotify/workProjectNotifyShowList.jsp

@@ -7,6 +7,21 @@
 	<meta name="decorator" content="default"/>
 	<script type="text/javascript">
 		$(document).ready(function() {
+			// 按权限加载通知页面类型下拉框
+			var currentTypeVal = '${workProjectNotify.types}';
+			$.ajax({
+				url: '${ctx}/sysMenuDictRelation/getNotifyDictValuesByPermission',
+				type: 'GET',
+				success: function(data) {
+					var select = $('#types');
+					select.empty().append('<option value=""></option>');
+					$.each(data, function(i, item) {
+						var selected = (item.value == currentTypeVal) ? ' selected' : '';
+						select.append('<option value="' + item.value + '"' + selected + '>' + item.label + '</option>');
+					});
+					layui.form.render('select');
+				}
+			});
 		});
         function openDialogre(title,url,width,height,target){
             if(navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i)){//如果是移动端,就使用自适应大小弹窗
@@ -154,10 +169,9 @@
 						<div class="layui-item query athird">
 							<label class="layui-form-label">类型:</label>
 							<div class="layui-input-block">
-								<form:select id="types" path="types" class="form-control simple-select">
-									<form:option value="" label=""/>
-									<form:options items="${fns:getDictList('new_project_notify_type')}" itemLabel="label" itemValue="value" htmlEscape="false"/>
-								</form:select>
+								<select id="types" name="types" class="form-control simple-select">
+									<option value=""></option>
+								</select>
 							</div>
 						</div>
 						<div class="layui-item athird">