gufj il y a 6 mois
commit
27d04f9cd4
100 fichiers modifiés avec 6472 ajouts et 0 suppressions
  1. 25 0
      .gitignore
  2. 0 0
      LICENSE
  3. 0 0
      README.md
  4. 35 0
      bound-link-api/.gitignore
  5. 27 0
      bound-link-api/blink-admin/pom.xml
  6. 39 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/config/MvcConfig.java
  7. 25 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/config/OperateLogAspectConfig.java
  8. 56 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/constant/AdminCacheConst.java
  9. 16 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/constant/AdminRedisKeyConst.java
  10. 56 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/constant/AdminSwaggerTagConst.java
  11. 186 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/interceptor/AdminInterceptor.java
  12. 22 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/listener/AdminStartupRunner.java
  13. 35 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/constant/CategoryTypeEnum.java
  14. 68 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/controller/CategoryController.java
  15. 62 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/dao/CategoryDao.java
  16. 44 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/dto/CategoryBaseDTO.java
  17. 26 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/dto/CategorySimpleDTO.java
  18. 66 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/entity/CategoryEntity.java
  19. 47 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/form/CategoryAddForm.java
  20. 24 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/form/CategoryTreeQueryForm.java
  21. 22 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/form/CategoryUpdateForm.java
  22. 39 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/vo/CategoryTreeVO.java
  23. 45 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/vo/CategoryVO.java
  24. 112 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/manager/CategoryCacheManager.java
  25. 187 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/service/CategoryQueryService.java
  26. 205 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/service/CategoryService.java
  27. 41 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/constant/GoodsStatusEnum.java
  28. 93 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/controller/GoodsController.java
  29. 37 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/dao/GoodsDao.java
  30. 70 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/entity/GoodsEntity.java
  31. 55 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/form/GoodsAddForm.java
  32. 36 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/form/GoodsImportForm.java
  33. 44 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/form/GoodsQueryForm.java
  34. 22 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/form/GoodsUpdateForm.java
  35. 42 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/vo/GoodsExcelVO.java
  36. 55 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/vo/GoodsVO.java
  37. 210 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/service/GoodsService.java
  38. 73 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/BankController.java
  39. 47 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/BankDao.java
  40. 144 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/BankService.java
  41. 57 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/domain/BankCreateForm.java
  42. 94 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/domain/BankEntity.java
  43. 39 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/domain/BankQueryForm.java
  44. 22 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/domain/BankUpdateForm.java
  45. 57 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/domain/BankVO.java
  46. 133 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/EnterpriseController.java
  47. 18 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/EnterpriseEmployeeManager.java
  48. 237 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/EnterpriseService.java
  49. 45 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/constant/EnterpriseTypeEnum.java
  50. 64 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/dao/EnterpriseDao.java
  51. 69 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/dao/EnterpriseEmployeeDao.java
  52. 50 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/entity/EnterpriseEmployeeEntity.java
  53. 152 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/entity/EnterpriseEntity.java
  54. 100 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseCreateForm.java
  55. 28 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseEmployeeForm.java
  56. 32 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseEmployeeQueryForm.java
  57. 37 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseQueryForm.java
  58. 22 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseUpdateForm.java
  59. 46 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseEmployeeVO.java
  60. 47 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseExcelVO.java
  61. 20 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseListVO.java
  62. 88 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseVO.java
  63. 79 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/InvoiceController.java
  64. 60 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/InvoiceDao.java
  65. 142 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/InvoiceService.java
  66. 58 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/domain/InvoiceAddForm.java
  67. 97 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/domain/InvoiceEntity.java
  68. 39 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/domain/InvoiceQueryForm.java
  69. 22 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/domain/InvoiceUpdateForm.java
  70. 57 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/domain/InvoiceVO.java
  71. 35 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/constant/NoticeVisibleRangeDataTypeEnum.java
  72. 139 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/controller/NoticeController.java
  73. 125 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/dao/NoticeDao.java
  74. 20 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/dao/NoticeTypeDao.java
  75. 98 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/entity/NoticeEntity.java
  76. 40 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/entity/NoticeTypeEntity.java
  77. 77 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeAddForm.java
  78. 34 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeEmployeeQueryForm.java
  79. 47 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeQueryForm.java
  80. 23 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeUpdateForm.java
  81. 31 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeViewRecordQueryForm.java
  82. 33 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeVisibleRangeForm.java
  83. 83 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeDetailVO.java
  84. 25 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeEmployeeVO.java
  85. 23 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeTypeVO.java
  86. 34 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeUpdateFormVO.java
  87. 72 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeVO.java
  88. 48 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeViewRecordVO.java
  89. 28 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeVisibleRangeVO.java
  90. 61 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/manager/NoticeManager.java
  91. 152 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/service/NoticeEmployeeService.java
  92. 235 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/service/NoticeService.java
  93. 86 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/service/NoticeTypeService.java
  94. 49 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/DataScope.java
  95. 37 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/DataScopeController.java
  96. 185 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/MyBatisPlugin.java
  97. 55 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/constant/DataScopeTypeEnum.java
  98. 64 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/constant/DataScopeViewTypeEnum.java
  99. 50 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/constant/DataScopeWhereInTypeEnum.java
  100. 34 0
      bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/domain/DataScopeAndViewTypeVO.java

+ 25 - 0
.gitignore

@@ -0,0 +1,25 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/src/test/**
+
+### STS ###
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### front ###
+**/dist
+**/node_modules
+**/.vscode
+

+ 0 - 0
LICENSE


+ 0 - 0
README.md


+ 35 - 0
bound-link-api/.gitignore

@@ -0,0 +1,35 @@
+HELP.md
+target/
+
+velocity.log
+
+!.mvn/wrapper/maven-wrapper.jar
+
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+.DS_Store
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+
+### VS Code ###
+.vscode/

+ 27 - 0
bound-link-api/blink-admin/pom.xml

@@ -0,0 +1,27 @@
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.cloud</groupId>
+        <artifactId>blink-parent</artifactId>
+        <version>3.0.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>blink-admin</artifactId>
+    <version>3.0.0</version>
+    <packaging>jar</packaging>
+
+    <name>blink-admin</name>
+    <description>blink-admin project</description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>com.cloud</groupId>
+            <artifactId>blink-base</artifactId>
+            <version>3.0.0</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 39 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/config/MvcConfig.java

@@ -0,0 +1,39 @@
+package com.cloud.sa.admin.config;
+
+import com.cloud.sa.admin.interceptor.AdminInterceptor;
+import com.cloud.sa.base.config.SwaggerConfig;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import javax.annotation.Resource;
+
+/**
+ * web相关配置
+ *
+ * @Author 畅联云: admin
+ * @Date 2021-09-02 20:21:10
+ */
+@Configuration
+public class MvcConfig implements WebMvcConfigurer {
+
+    @Resource
+    private AdminInterceptor adminInterceptor;
+
+
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(adminInterceptor)
+                .excludePathPatterns(SwaggerConfig.SWAGGER_WHITELIST)
+                .addPathPatterns("/**");
+    }
+
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
+        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
+    }
+
+}

+ 25 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/config/OperateLogAspectConfig.java

@@ -0,0 +1,25 @@
+package com.cloud.sa.admin.config;
+
+import com.cloud.sa.base.module.support.operatelog.core.OperateLogAspect;
+import com.cloud.sa.base.module.support.operatelog.core.OperateLogConfig;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 操作日志切面 配置
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-05-30 21:22:12
+ */
+@Configuration
+public class OperateLogAspectConfig extends OperateLogAspect{
+
+    /**
+     * 配置信息
+     */
+    @Override
+    public OperateLogConfig getOperateLogConfig() {
+        return OperateLogConfig.builder().corePoolSize(1).queueCapacity(10000).build();
+    }
+
+
+}

+ 56 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/constant/AdminCacheConst.java

@@ -0,0 +1,56 @@
+package com.cloud.sa.admin.constant;
+
+import com.cloud.sa.base.constant.CacheKeyConst;
+
+/**
+ * 缓存 key
+ *
+ * @Author 云畅联:admin
+ * @Date 2022-01-07 18:59:22
+
+ * 
+ */
+public class AdminCacheConst extends CacheKeyConst {
+
+    public static class Department {
+
+        /**
+         * 部门列表
+         */
+        public static final String DEPARTMENT_LIST_CACHE = "department_list_cache";
+
+        /**
+         * 部门map
+         */
+        public static final String DEPARTMENT_MAP_CACHE = "department_map_cache";
+
+        /**
+         * 部门树
+         */
+        public static final String DEPARTMENT_TREE_CACHE = "department_tree_cache";
+
+        /**
+         * 某个部门以及下级的id列表
+         */
+        public static final String DEPARTMENT_SELF_CHILDREN_CACHE = "department_self_children_cache";
+
+        /**
+         * 部门路径 缓存
+         */
+        public static final String DEPARTMENT_PATH_CACHE = "department_path_cache";
+
+    }
+
+    /**
+     * 分类相关缓存
+     */
+    public static class Category {
+
+        public static final String CATEGORY_ENTITY = "category_cache";
+
+        public static final String CATEGORY_SUB = "category_sub_cache";
+
+        public static final String CATEGORY_TREE = "category_tree_cache";
+    }
+
+}

+ 16 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/constant/AdminRedisKeyConst.java

@@ -0,0 +1,16 @@
+package com.cloud.sa.admin.constant;
+
+import com.cloud.sa.base.constant.RedisKeyConst;
+
+/**
+ * redis key 常量类
+ *
+ * @Author 云畅联:admin
+ * @Date 2022-01-07 18:59:22
+
+ *
+ */
+public class AdminRedisKeyConst extends RedisKeyConst {
+
+
+}

+ 56 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/constant/AdminSwaggerTagConst.java

@@ -0,0 +1,56 @@
+package com.cloud.sa.admin.constant;
+
+import com.cloud.sa.base.constant.SwaggerTagConst;
+
+/**
+ * swagger
+ *
+ * @Author 云畅联:admin
+ * @Date 2022-01-07 18:59:22
+
+ *
+ */
+public class AdminSwaggerTagConst extends SwaggerTagConst {
+
+    public static class Business {
+        public static final String MANAGER_CATEGORY = "ERP进销存-分类管理";
+
+        public static final String MANAGER_GOODS = "ERP进销存-商品管理";
+
+        public static final String OA_BANK = "OA办公-银行卡信息";
+
+        public static final String OA_ENTERPRISE = "OA办公-企业";
+
+        public static final String OA_INVOICE = "OA办公-发票信息";
+
+        public static final String OA_NOTICE = "OA办公-通知公告";
+
+    }
+
+
+    public static class System {
+
+        public static final String SYSTEM_LOGIN = "系统-员工登录";
+
+        public static final String SYSTEM_EMPLOYEE = "系统-员工管理";
+
+        public static final String SYSTEM_DEPARTMENT = "系统-部门管理";
+
+        public static final String SYSTEM_MENU = "系统-菜单";
+
+        public static final String SYSTEM_DATA_SCOPE = "系统-系统-数据范围";
+
+        public static final String SYSTEM_ROLE = "系统-角色";
+
+        public static final String SYSTEM_ROLE_DATA_SCOPE = "系统-角色-数据范围";
+
+        public static final String SYSTEM_ROLE_EMPLOYEE = "系统-角色-员工";
+
+        public static final String SYSTEM_ROLE_MENU = "系统-角色-菜单";
+
+        public static final String SYSTEM_POSITION = "系统-职务管理";
+
+    }
+
+
+}

+ 186 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/interceptor/AdminInterceptor.java

@@ -0,0 +1,186 @@
+package com.cloud.sa.admin.interceptor;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.dev33.satoken.exception.SaTokenException;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.strategy.SaStrategy;
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+import com.cloud.sa.admin.module.system.login.domain.RequestEmployee;
+import com.cloud.sa.admin.module.system.login.service.LoginService;
+import com.cloud.sa.base.common.annoation.NoNeedLogin;
+import com.cloud.sa.base.common.code.SystemErrorCode;
+import com.cloud.sa.base.common.code.UserErrorCode;
+import com.cloud.sa.base.common.constant.StringConst;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.domain.SystemEnvironment;
+import com.cloud.sa.base.common.enumeration.SystemEnvironmentEnum;
+import com.cloud.sa.base.common.enumeration.UserTypeEnum;
+import com.cloud.sa.base.common.util.BlinkRequestUtil;
+import com.cloud.sa.base.common.util.BlinkResponseUtil;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+
+/**
+ * admin 拦截器
+ *
+ * @Author 云畅联:admin
+ * @Date 2023/7/26 20:20:33
+
+ * Since 2012
+ */
+
+@Component
+@Slf4j
+public class AdminInterceptor implements HandlerInterceptor {
+
+    @Resource
+    private LoginService loginService;
+
+    @Resource
+    private SystemEnvironment systemEnvironment;
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+
+        // OPTIONS请求直接return
+        if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
+            response.setStatus(HttpStatus.NO_CONTENT.value());
+            return false;
+        }
+
+        boolean isHandler = handler instanceof HandlerMethod;
+        if (!isHandler) {
+            return true;
+        }
+
+        try {
+            // --------------- 第一步: 根据token 获取用户 ---------------
+
+            String tokenValue = StpUtil.getTokenValue();
+            boolean debugNumberTokenFlag = isDevDebugNumberToken(tokenValue);
+
+            String loginId = null;
+            if (debugNumberTokenFlag) {
+                //开发、测试环境,且为数字的话,则表明为 调试临时用户,即需要调用 sa-token switch
+                loginId = UserTypeEnum.ADMIN_EMPLOYEE.getValue() + StringConst.COLON + tokenValue;
+                StpUtil.switchTo(loginId);
+            } else {
+                loginId = (String) StpUtil.getLoginIdByToken(tokenValue);
+            }
+
+            RequestEmployee requestEmployee = loginService.getLoginEmployee(loginId, request);
+
+            // --------------- 第二步: 校验 登录 ---------------
+
+            Method method = ((HandlerMethod) handler).getMethod();
+            NoNeedLogin noNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class);
+            if (noNeedLogin != null) {
+                checkActiveTimeout(requestEmployee,debugNumberTokenFlag);
+                return true;
+            }
+
+            if (requestEmployee == null) {
+                BlinkResponseUtil.write(response, ResponseDTO.error(UserErrorCode.LOGIN_STATE_INVALID));
+                return false;
+            }
+
+            // 检测token 活跃频率
+            checkActiveTimeout(requestEmployee,debugNumberTokenFlag);
+
+
+            // --------------- 第三步: 校验 权限 ---------------
+
+            BlinkRequestUtil.setRequestUser(requestEmployee);
+            if (SaStrategy.instance.isAnnotationPresent.apply(method, SaIgnore.class)) {
+                return true;
+            }
+
+            // 如果是超级管理员的话,不需要校验权限
+            if(requestEmployee.getAdministratorFlag()){
+               return true;
+            }
+
+            SaStrategy.instance.checkMethodAnnotation.accept(method);
+
+        } catch (SaTokenException e) {
+            /*
+             * sa-token 异常状态码
+             * 具体请看: https://sa-token.cc/doc.html#/fun/exception-code
+             */
+            int code = e.getCode();
+            if (code == 11041 || code == 11051) {
+                BlinkResponseUtil.write(response, ResponseDTO.error(UserErrorCode.NO_PERMISSION));
+            } else if (code == 11016) {
+                BlinkResponseUtil.write(response, ResponseDTO.error(UserErrorCode.LOGIN_ACTIVE_TIMEOUT));
+            } else if (code >= 11011 && code <= 11015) {
+                BlinkResponseUtil.write(response, ResponseDTO.error(UserErrorCode.LOGIN_STATE_INVALID));
+            } else {
+                BlinkResponseUtil.write(response, ResponseDTO.error(UserErrorCode.PARAM_ERROR));
+            }
+            return false;
+        } catch (Throwable e) {
+            BlinkResponseUtil.write(response, ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR));
+            log.error(e.getMessage(), e);
+            return false;
+        }
+
+        // 通过验证
+        return true;
+    }
+
+
+    /**
+     * 检测:token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结
+     */
+    private void checkActiveTimeout(RequestEmployee requestEmployee, boolean debugNumberTokenFlag) {
+
+        // 对于开发环境的 数字 debug token ,不需要检测活跃有效期
+        if (debugNumberTokenFlag) {
+            return;
+        }
+
+        // 用户不在线,也不用检测
+        if (requestEmployee == null) {
+            return;
+        }
+
+        StpUtil.checkActiveTimeout();
+        StpUtil.updateLastActiveToNow();
+    }
+
+
+    /**
+     * 是否为开发使用的 debug token
+     *
+     * @param token
+     * @return
+     */
+    private boolean isDevDebugNumberToken(String token) {
+        if (!StrUtil.isNumeric(token)) {
+            return false;
+        }
+        return systemEnvironment.getCurrentEnvironment() == SystemEnvironmentEnum.DEV
+                || systemEnvironment.getCurrentEnvironment() == SystemEnvironmentEnum.TEST;
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+        // 清除上下文
+        BlinkRequestUtil.remove();
+        // 开发环境,关闭 sa token 的临时切换用户
+        if (systemEnvironment.getCurrentEnvironment() == SystemEnvironmentEnum.DEV) {
+            StpUtil.endSwitch();
+        }
+    }
+
+
+}

+ 22 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/listener/AdminStartupRunner.java

@@ -0,0 +1,22 @@
+package com.cloud.sa.admin.listener;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+/**
+ * admin 应用启动加载
+ *
+ * @Author 云畅联:admin
+ * @Date 2021-08-26 18:46:32
+
+ */
+@Slf4j
+@Component
+public class AdminStartupRunner implements CommandLineRunner {
+
+
+    @Override
+    public void run(String... args) {
+    }
+}

+ 35 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/constant/CategoryTypeEnum.java

@@ -0,0 +1,35 @@
+package com.cloud.sa.admin.module.business.category.constant;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import com.cloud.sa.base.common.enumeration.BaseEnum;
+
+/**
+ * 分类类型 枚举
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ * 
+ */
+@AllArgsConstructor
+@Getter
+public enum CategoryTypeEnum implements BaseEnum {
+
+    /**
+     * 1 商品
+     */
+    GOODS(1, "商品"),
+
+    /**
+     * 2 自定义
+     */
+    CUSTOM(2, "自定义"),
+
+    ;
+
+    private final Integer value;
+
+    private final String desc;
+}

+ 68 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/controller/CategoryController.java

@@ -0,0 +1,68 @@
+package com.cloud.sa.admin.module.business.category.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.cloud.sa.admin.constant.AdminSwaggerTagConst;
+import com.cloud.sa.admin.module.business.category.domain.form.CategoryAddForm;
+import com.cloud.sa.admin.module.business.category.domain.form.CategoryUpdateForm;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import com.cloud.sa.admin.module.business.category.domain.form.CategoryTreeQueryForm;
+import com.cloud.sa.admin.module.business.category.domain.vo.CategoryTreeVO;
+import com.cloud.sa.admin.module.business.category.domain.vo.CategoryVO;
+import com.cloud.sa.admin.module.business.category.service.CategoryService;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 类目
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ * 
+ */
+@RestController
+@Tag(name = AdminSwaggerTagConst.Business.MANAGER_CATEGORY)
+public class CategoryController {
+
+    @Resource
+    private CategoryService categoryService;
+
+    @Operation(summary = "添加类目 @author admin")
+    @PostMapping("/category/add")
+    @SaCheckPermission("category:add")
+    public ResponseDTO<String> add(@RequestBody @Valid CategoryAddForm addForm) {
+        return categoryService.add(addForm);
+    }
+
+    @Operation(summary = "更新类目 @author admin")
+    @PostMapping("/category/update")
+    @SaCheckPermission("category:update")
+    public ResponseDTO<String> update(@RequestBody @Valid CategoryUpdateForm updateForm) {
+        return categoryService.update(updateForm);
+    }
+
+    @Operation(summary = "查询类目详情 @author admin")
+    @GetMapping("/category/{categoryId}")
+    public ResponseDTO<CategoryVO> queryDetail(@PathVariable Long categoryId) {
+        return categoryService.queryDetail(categoryId);
+    }
+
+    @Operation(summary = "查询类目层级树 @author admin")
+    @PostMapping("/category/tree")
+    @SaCheckPermission("category:tree")
+    public ResponseDTO<List<CategoryTreeVO>> queryTree(@RequestBody @Valid CategoryTreeQueryForm queryForm) {
+        return categoryService.queryTree(queryForm);
+    }
+
+    @Operation(summary = "删除类目 @author admin")
+    @GetMapping("/category/delete/{categoryId}")
+    @SaCheckPermission("category:delete")
+    public ResponseDTO<String> delete(@PathVariable Long categoryId) {
+        return categoryService.delete(categoryId);
+    }
+}

+ 62 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/dao/CategoryDao.java

@@ -0,0 +1,62 @@
+package com.cloud.sa.admin.module.business.category.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cloud.sa.admin.module.business.category.constant.CategoryTypeEnum;
+import com.cloud.sa.admin.module.business.category.domain.entity.CategoryEntity;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 类目 dao
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ * 
+ */
+@Component
+@Mapper
+public interface CategoryDao extends BaseMapper<CategoryEntity> {
+
+    /**
+     * 根据父级id 类型 查询子类
+     *
+     * @param parentIdList 父级id集合
+     * @param deletedFlag 删除标识
+     * @return 列表
+     */
+    List<CategoryEntity> queryByParentId(@Param("parentIdList") List<Long> parentIdList,
+                                         @Param("deletedFlag") Boolean deletedFlag);
+
+    /**
+     * 根据父级id 类型 查询子类
+     *
+     * @param parentIdList 父级id集合
+     * @param categoryType {@link CategoryTypeEnum}
+     * @param deletedFlag 删除标识
+     * @return 列表
+     */
+    List<CategoryEntity> queryByParentIdAndType(@Param("parentIdList") List<Long> parentIdList,
+                                         @Param("categoryType") Integer categoryType,
+                                         @Param("deletedFlag") Boolean deletedFlag);
+
+    /**
+     * 某个类型的所有
+     */
+    List<CategoryEntity> queryByType(@Param("categoryType") Integer categoryType,
+                                                @Param("deletedFlag") Boolean deletedFlag);
+
+    /**
+     * 根据类型和id查询
+     */
+    CategoryEntity selectByTypeAndId(@Param("categoryType") Integer categoryType, @Param("categoryId") Long categoryId);
+
+    /**
+     * 查看类目 具体条件 看sql
+     */
+    CategoryEntity selectOne(CategoryEntity entity);
+
+}

+ 44 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/dto/CategoryBaseDTO.java

@@ -0,0 +1,44 @@
+package com.cloud.sa.admin.module.business.category.domain.dto;
+
+import com.cloud.sa.admin.module.business.category.constant.CategoryTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+import com.cloud.sa.base.common.validator.enumeration.CheckEnum;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 类目 基础属性 DTO 类
+ *
+ * @author admin
+ * @date 2021/1/20 16:17
+ */
+@Data
+public class CategoryBaseDTO {
+
+    @Schema(description = "类目名称", required = true)
+    @NotBlank(message = "类目名称不能为空")
+    @Length(max = 20, message = "类目名称最多20字符")
+    private String categoryName;
+
+    @SchemaEnum(desc = "分类类型", value = CategoryTypeEnum.class)
+    @CheckEnum(value = CategoryTypeEnum.class, required = true, message = "分类错误")
+    private Integer categoryType;
+
+    @Schema(description = "父级类目id|可选")
+    private Long parentId;
+
+    @Schema(description = "排序|可选")
+    private Integer sort;
+
+    @Schema(description = "备注|可选")
+    @Length(max = 200, message = "备注最多200字符")
+    private String remark;
+
+    @Schema(description = "禁用状态")
+    @NotNull(message = "禁用状态不能为空")
+    private Boolean disabledFlag;
+}

+ 26 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/dto/CategorySimpleDTO.java

@@ -0,0 +1,26 @@
+package com.cloud.sa.admin.module.business.category.domain.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 类目 基础属性 DTO 类
+ *
+ * @author admin
+ * @date 2021/1/20 16:17
+ */
+@Data
+public class CategorySimpleDTO {
+
+    @Schema(description = "类目id")
+    private Long categoryId;
+
+    @Schema(description = "类目名称")
+    private String categoryName;
+
+    @Schema(description = "类目层级全称")
+    private String categoryFullName;
+
+    @Schema(description = "父级id")
+    private Long parentId;
+}

+ 66 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/entity/CategoryEntity.java

@@ -0,0 +1,66 @@
+package com.cloud.sa.admin.module.business.category.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import com.cloud.sa.admin.module.business.category.constant.CategoryTypeEnum;
+
+import java.time.LocalDateTime;
+
+/**
+ * 类目 实体类
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ *
+ */
+@Data
+@TableName("t_category")
+public class CategoryEntity {
+
+    @TableId(type = IdType.AUTO)
+    private Long categoryId;
+
+    /**
+     * 类目名称
+     */
+    private String categoryName;
+
+    /**
+     * 类目 类型
+     *
+     * @see CategoryTypeEnum
+     */
+    private Integer categoryType;
+
+    /**
+     * 父级类目id
+     */
+    private Long parentId;
+
+    /**
+     * 是否禁用
+     */
+    private Boolean disabledFlag;
+
+    /**
+     * 排序
+     */
+    private Integer sort;
+
+    /**
+     * 删除状态
+     */
+    private Boolean deletedFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    private LocalDateTime updateTime;
+
+    private LocalDateTime createTime;
+}

+ 47 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/form/CategoryAddForm.java

@@ -0,0 +1,47 @@
+package com.cloud.sa.admin.module.business.category.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.admin.module.business.category.constant.CategoryTypeEnum;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+import com.cloud.sa.base.common.validator.enumeration.CheckEnum;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 类目 添加
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ *
+ */
+@Data
+public class CategoryAddForm {
+
+    @Schema(description = "类目名称", required = true)
+    @NotBlank(message = "类目名称不能为空")
+    @Length(max = 20, message = "类目名称最多20字符")
+    private String categoryName;
+
+    @SchemaEnum(desc = "分类类型", value = CategoryTypeEnum.class)
+    @CheckEnum(value = CategoryTypeEnum.class, required = true, message = "分类错误")
+    private Integer categoryType;
+
+    @Schema(description = "父级类目id|可选")
+    private Long parentId;
+
+    @Schema(description = "排序|可选")
+    private Integer sort;
+
+    @Schema(description = "备注|可选")
+    @Length(max = 200, message = "备注最多200字符")
+    private String remark;
+
+    @Schema(description = "禁用状态")
+    @NotNull(message = "禁用状态不能为空")
+    private Boolean disabledFlag;
+
+}

+ 24 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/form/CategoryTreeQueryForm.java

@@ -0,0 +1,24 @@
+package com.cloud.sa.admin.module.business.category.domain.form;
+
+import com.cloud.sa.admin.module.business.category.constant.CategoryTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+
+/**
+ * 类目 层级树查询
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ *
+ */
+@Data
+public class CategoryTreeQueryForm {
+
+    @SchemaEnum(desc = "分类类型|可选", value = CategoryTypeEnum.class)
+    private Integer categoryType;
+
+    @Schema(description = "父级类目id|可选")
+    private Long parentId;
+}

+ 22 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/form/CategoryUpdateForm.java

@@ -0,0 +1,22 @@
+package com.cloud.sa.admin.module.business.category.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 类目 更新
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ *
+ */
+@Data
+public class CategoryUpdateForm extends CategoryAddForm {
+
+    @Schema(description = "类目id")
+    @NotNull(message = "类目id不能为空")
+    private Long categoryId;
+}

+ 39 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/vo/CategoryTreeVO.java

@@ -0,0 +1,39 @@
+package com.cloud.sa.admin.module.business.category.domain.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 类目 层级树 vo
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ *
+ */
+@Data
+public class CategoryTreeVO {
+
+    @Schema(description = "类目id")
+    private Long categoryId;
+
+    @Schema(description = "类目名称")
+    private String categoryName;
+
+    @Schema(description = "类目层级全称")
+    private String categoryFullName;
+
+    @Schema(description = "父级id")
+    private Long parentId;
+
+    @Schema(description = "类目id")
+    private Long value;
+
+    @Schema(description = "类目名称")
+    private String label;
+
+    @Schema(description = "子类")
+    private List<CategoryTreeVO> children;
+}

+ 45 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/domain/vo/CategoryVO.java

@@ -0,0 +1,45 @@
+package com.cloud.sa.admin.module.business.category.domain.vo;
+
+import com.cloud.sa.admin.module.business.category.constant.CategoryTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+
+import java.time.LocalDateTime;
+
+/**
+ * 类目
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ * 
+ */
+@Data
+public class CategoryVO {
+
+    @Schema(description = "类目名称", required = true)
+    private String categoryName;
+
+    @SchemaEnum(desc = "分类类型", value = CategoryTypeEnum.class)
+    private Integer categoryType;
+
+    @Schema(description = "父级类目id|可选")
+    private Long parentId;
+
+    @Schema(description = "排序|可选")
+    private Integer sort;
+
+    @Schema(description = "备注|可选")
+    private String remark;
+
+    @Schema(description = "禁用状态")
+    private Boolean disabledFlag;
+
+    @Schema(description = "类目id")
+    private Long categoryId;
+
+    private LocalDateTime updateTime;
+
+    private LocalDateTime createTime;
+}

+ 112 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/manager/CategoryCacheManager.java

@@ -0,0 +1,112 @@
+package com.cloud.sa.admin.module.business.category.manager;
+
+import com.cloud.sa.admin.constant.AdminCacheConst;
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import com.cloud.sa.admin.module.business.category.dao.CategoryDao;
+import com.cloud.sa.admin.module.business.category.domain.entity.CategoryEntity;
+import com.cloud.sa.admin.module.business.category.domain.vo.CategoryTreeVO;
+import com.cloud.sa.base.common.constant.StringConst;
+import com.cloud.sa.base.common.util.BlinkBeanUtil;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 类目 查询 缓存
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ *
+ */
+@Service
+@Slf4j
+public class CategoryCacheManager {
+
+
+    @Resource
+    private CategoryDao categoryDao;
+
+
+    /**
+     * 根据类目id 移除缓存
+     */
+    @CacheEvict(value = {AdminCacheConst.Category.CATEGORY_ENTITY, AdminCacheConst.Category.CATEGORY_SUB, AdminCacheConst.Category.CATEGORY_TREE}, allEntries = true)
+    public void removeCache() {
+        log.info("clear CATEGORY ,CATEGORY_SUB ,CATEGORY_TREE");
+    }
+
+    /**
+     * 查詢类目
+     *
+     */
+    @Cacheable(AdminCacheConst.Category.CATEGORY_ENTITY)
+    public CategoryEntity queryCategory(Long categoryId) {
+        return categoryDao.selectById(categoryId);
+    }
+
+    /**
+     * 查询类目 子级
+     *
+     */
+    @Cacheable(AdminCacheConst.Category.CATEGORY_SUB)
+    public List<CategoryEntity> querySubCategory(Long categoryId) {
+        return categoryDao.queryByParentId(Lists.newArrayList(categoryId), false);
+    }
+
+
+    /**
+     * 查询类目 层级树
+     * 优先查询缓存
+     */
+    @Cacheable(AdminCacheConst.Category.CATEGORY_TREE)
+    public List<CategoryTreeVO> queryCategoryTree(Long parentId, Integer categoryType) {
+        List<CategoryEntity> allCategoryEntityList = categoryDao.queryByType(categoryType, false);
+
+        List<CategoryEntity> categoryEntityList = allCategoryEntityList.stream().filter(e -> e.getParentId().equals(parentId)).collect(Collectors.toList());
+        List<CategoryTreeVO> treeList = BlinkBeanUtil.copyList(categoryEntityList, CategoryTreeVO.class);
+        treeList.forEach(e -> {
+            e.setLabel(e.getCategoryName());
+            e.setValue(e.getCategoryId());
+            e.setCategoryFullName(e.getCategoryName());
+        });
+        // 递归设置子类
+        this.queryAndSetSubCategory(treeList, allCategoryEntityList);
+        return treeList;
+    }
+
+    /**
+     * 递归查询设置类目子类
+     * 从缓存查询子类
+     *
+     */
+    private void queryAndSetSubCategory(List<CategoryTreeVO> treeList, List<CategoryEntity> allCategoryEntityList) {
+        if (CollectionUtils.isEmpty(treeList)) {
+            return;
+        }
+        List<Long> parentIdList = treeList.stream().map(CategoryTreeVO::getValue).collect(Collectors.toList());
+        List<CategoryEntity> categoryEntityList = allCategoryEntityList.stream().filter(e -> parentIdList.contains(e.getParentId())).collect(Collectors.toList());
+        Map<Long, List<CategoryEntity>> categorySubMap = categoryEntityList.stream().collect(Collectors.groupingBy(CategoryEntity::getParentId));
+        treeList.forEach(e -> {
+            List<CategoryEntity> childrenEntityList = categorySubMap.getOrDefault(e.getValue(), Lists.newArrayList());
+            List<CategoryTreeVO> childrenVOList = BlinkBeanUtil.copyList(childrenEntityList, CategoryTreeVO.class);
+            childrenVOList.forEach(item -> {
+                item.setLabel(item.getCategoryName());
+                item.setValue(item.getCategoryId());
+                item.setCategoryFullName(e.getCategoryFullName() + StringConst.SEPARATOR_SLASH + item.getCategoryName());
+            });
+            // 递归查询
+            this.queryAndSetSubCategory(childrenVOList, allCategoryEntityList);
+            e.setChildren(childrenVOList);
+        });
+    }
+
+
+}

+ 187 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/service/CategoryQueryService.java

@@ -0,0 +1,187 @@
+package com.cloud.sa.admin.module.business.category.service;
+
+import cn.hutool.core.util.StrUtil;
+import com.cloud.sa.admin.module.business.category.domain.entity.CategoryEntity;
+import com.cloud.sa.admin.module.business.category.manager.CategoryCacheManager;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import lombok.extern.slf4j.Slf4j;
+import com.cloud.sa.admin.module.business.category.domain.dto.CategorySimpleDTO;
+import com.cloud.sa.base.common.constant.StringConst;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 类目 查询 业务类
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ * 
+ */
+@Service
+@Slf4j
+public class CategoryQueryService {
+
+    private static final Long DEFAULT_CATEGORY_PARENT_ID = 0L;
+
+    @Resource
+    private CategoryCacheManager categoryCacheManager;
+
+    /**
+     * 根据 id 查询未删除的类目
+     *
+     * @param categoryId
+     * @return 可能 null
+     */
+    public Optional<CategoryEntity> queryCategory(Long categoryId) {
+        if (null == categoryId) {
+            return Optional.empty();
+        }
+        CategoryEntity entity = categoryCacheManager.queryCategory(categoryId);
+        if (null == entity || entity.getDeletedFlag()) {
+            return Optional.empty();
+        }
+        return Optional.of(entity);
+    }
+
+
+    /**
+     * 根据 类目id集合 查询未删除的类目集合
+     */
+    public Map<Long, CategoryEntity> queryCategoryList(List<Long> categoryIdList) {
+        if (CollectionUtils.isEmpty(categoryIdList)) {
+            return Collections.emptyMap();
+        }
+        categoryIdList = categoryIdList.stream().distinct().collect(Collectors.toList());
+        Map<Long, CategoryEntity> categoryEntityMap = Maps.newHashMap();
+        for (Long categoryId : categoryIdList) {
+            CategoryEntity categoryEntity = categoryCacheManager.queryCategory(categoryId);
+            if (categoryEntity != null) {
+                categoryEntityMap.put(categoryId, categoryEntity);
+            }
+        }
+        return categoryEntityMap;
+    }
+
+
+    /**
+     * 根据类目id 递归查询该id的所有子类id 递归查询
+     * 同时存入缓存
+     * 注意:查询出来的集合 不包含传递的父类参数
+     */
+    public List<Long> queryCategorySubId(List<Long> categoryIdList) {
+        if (CollectionUtils.isEmpty(categoryIdList)) {
+            return Collections.emptyList();
+        }
+        //所有子类
+        List<CategoryEntity> categoryEntityList = Lists.newArrayList();
+        categoryIdList.forEach(e -> {
+            categoryEntityList.addAll(categoryCacheManager.querySubCategory(e));
+        });
+        Map<Long, List<CategoryEntity>> subTypeMap = categoryEntityList.stream().collect(Collectors.groupingBy(CategoryEntity::getCategoryId));
+        // 递归查询子类
+        categoryIdList = subTypeMap.values().stream().flatMap(Collection::stream).map(CategoryEntity::getCategoryId).distinct().collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(categoryIdList)) {
+            return Lists.newArrayList();
+        }
+        categoryIdList.addAll(this.queryCategorySubId(categoryIdList));
+        return categoryIdList;
+    }
+
+
+    /**
+     * 处理类目名称
+     */
+    public List<String> queryCategoryName(List<Long> categoryIdList) {
+        if (CollectionUtils.isEmpty(categoryIdList)) {
+            return null;
+        }
+        Map<Long, CategoryEntity> categoryMap = this.queryCategoryList(categoryIdList);
+        List<String> categoryNameList = Lists.newArrayList();
+        categoryIdList.forEach(e -> {
+            CategoryEntity categoryEntity = categoryMap.get(e);
+            if (categoryEntity != null) {
+                categoryNameList.add(categoryMap.get(e).getCategoryName());
+            }
+        });
+        return categoryNameList;
+    }
+
+    /**
+     * 根据类目id 查询类目名称
+     */
+    public String queryCategoryName(Long categoryId) {
+        CategoryEntity categoryEntity = categoryCacheManager.queryCategory(categoryId);
+        if (null == categoryEntity || categoryEntity.getDeletedFlag()) {
+            return null;
+        }
+        return categoryEntity.getCategoryName();
+    }
+
+    /**
+     * 根据类目id 查询类目详情 包含类目全称 如:医考/医师资格/临床执业
+     */
+    public CategorySimpleDTO queryCategoryInfo(Long categoryId) {
+        CategoryEntity categoryEntity = categoryCacheManager.queryCategory(categoryId);
+        if (null == categoryEntity || categoryEntity.getDeletedFlag()) {
+            return null;
+        }
+        String fullName = this.queryFullName(categoryId);
+        // 返回DTO
+        CategorySimpleDTO categoryDTO = new CategorySimpleDTO();
+        categoryDTO.setCategoryId(categoryId);
+        categoryDTO.setCategoryName(categoryEntity.getCategoryName());
+        categoryDTO.setCategoryFullName(fullName);
+        categoryDTO.setParentId(categoryEntity.getParentId());
+        return categoryDTO;
+    }
+
+    /**
+     * 递归查询分类和所有父级类目
+     * ps:特别注意返回的集合中 包含自己
+     */
+    public List<CategoryEntity> queryCategoryAndParent(Long categoryId) {
+        List<CategoryEntity> parentCategoryList = Lists.newArrayList();
+        CategoryEntity categoryEntity = categoryCacheManager.queryCategory(categoryId);
+        if (null == categoryEntity || categoryEntity.getDeletedFlag()) {
+            return parentCategoryList;
+        }
+
+        // 父级始终放在第一位
+        parentCategoryList.add(0, categoryEntity);
+        Long parentId = categoryEntity.getParentId();
+        if (Objects.equals(DEFAULT_CATEGORY_PARENT_ID, parentId)) {
+            return parentCategoryList;
+        }
+        parentCategoryList.addAll(0, this.queryCategoryAndParent(parentId));
+        return parentCategoryList;
+    }
+
+    /**
+     * 查询 分类全称 如:医考/医师资格/临床执业
+     */
+    public String queryFullName(Long categoryId) {
+        List<CategoryEntity> parentCategoryList = this.queryCategoryAndParent(categoryId);
+        // 拼接父级类目名称 斜杠分隔返回
+        List<String> nameList = parentCategoryList.stream().map(CategoryEntity::getCategoryName).collect(Collectors.toList());
+        return StrUtil.join(StringConst.SEPARATOR_SLASH, nameList);
+    }
+
+    /**
+     * 查询 分类全称 如:医考/医师资格/临床执业
+     */
+    public Map<Long, String> queryFullName(List<Long> categoryIdList) {
+        if (CollectionUtils.isEmpty(categoryIdList)) {
+            return Maps.newHashMap();
+        }
+        // 循环内查询的缓存 还ok
+        return categoryIdList.stream().collect(Collectors.toMap(Function.identity(), this::queryFullName));
+    }
+
+}

+ 205 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/category/service/CategoryService.java

@@ -0,0 +1,205 @@
+package com.cloud.sa.admin.module.business.category.service;
+
+import com.cloud.sa.admin.module.business.category.domain.entity.CategoryEntity;
+import com.cloud.sa.admin.module.business.category.domain.form.CategoryAddForm;
+import com.cloud.sa.admin.module.business.category.domain.form.CategoryUpdateForm;
+import com.cloud.sa.admin.module.business.category.manager.CategoryCacheManager;
+import com.google.common.collect.Lists;
+import com.cloud.sa.admin.module.business.category.dao.CategoryDao;
+import com.cloud.sa.admin.module.business.category.domain.form.CategoryTreeQueryForm;
+import com.cloud.sa.admin.module.business.category.domain.vo.CategoryTreeVO;
+import com.cloud.sa.admin.module.business.category.domain.vo.CategoryVO;
+import com.cloud.sa.base.common.code.UserErrorCode;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.util.BlinkBeanUtil;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * 类目
+ *
+ * @Author 云畅联: admin
+ * @Date 2021/08/05 21:26:58
+
+ * 
+ */
+@Service
+public class CategoryService {
+
+    @Resource
+    private CategoryDao categoryDao;
+
+    @Resource
+    private CategoryQueryService categoryQueryService;
+
+    @Resource
+    private CategoryCacheManager categoryCacheManager;
+
+    /**
+     * 添加类目
+     */
+    public ResponseDTO<String> add(CategoryAddForm addForm) {
+        // 校验类目
+        CategoryEntity categoryEntity = BlinkBeanUtil.copy(addForm, CategoryEntity.class);
+        ResponseDTO<String> res = this.checkCategory(categoryEntity, false);
+        if (!res.getOk()) {
+            return res;
+        }
+        // 没有父类则使用默认父类
+        Long parentId = null == addForm.getParentId() ? NumberUtils.LONG_ZERO : addForm.getParentId();
+        categoryEntity.setParentId(parentId);
+        categoryEntity.setSort(null == addForm.getSort() ? 0 : addForm.getSort());
+        categoryEntity.setDeletedFlag(false);
+
+        // 保存数据
+        categoryDao.insert(categoryEntity);
+
+        // 更新缓存
+        categoryCacheManager.removeCache();
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 更新类目
+     * 不能更新父级类目
+     *
+     */
+    public ResponseDTO<String> update(CategoryUpdateForm updateForm) {
+        // 校验类目
+        Long categoryId = updateForm.getCategoryId();
+        Optional<CategoryEntity> optional = categoryQueryService.queryCategory(categoryId);
+        if (!optional.isPresent()) {
+            return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST);
+        }
+        CategoryEntity categoryEntity = BlinkBeanUtil.copy(updateForm, CategoryEntity.class);
+
+        /*
+          不更新类目类型
+          不更新父类id
+         */
+        Integer categoryType = optional.get().getCategoryType();
+        categoryEntity.setCategoryType(categoryType);
+        categoryEntity.setParentId(optional.get().getParentId());
+
+        ResponseDTO<String> responseDTO = this.checkCategory(categoryEntity, true);
+        if (!responseDTO.getOk()) {
+            return responseDTO;
+        }
+        categoryDao.updateById(categoryEntity);
+
+        // 更新缓存
+        categoryCacheManager.removeCache();
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 新增/更新 类目时的 校验
+     *
+     */
+    private ResponseDTO<String> checkCategory(CategoryEntity categoryEntity, boolean isUpdate) {
+        // 校验父级是否存在
+        Long parentId = categoryEntity.getParentId();
+        Integer categoryType = categoryEntity.getCategoryType();
+        if (null != parentId) {
+            if (Objects.equals(categoryEntity.getCategoryId(), parentId)) {
+                return ResponseDTO.userErrorParam("父级类目怎么和自己相同了");
+            }
+            if (!Objects.equals(parentId, NumberUtils.LONG_ZERO)) {
+                Optional<CategoryEntity> optional = categoryQueryService.queryCategory(parentId);
+                if (!optional.isPresent()) {
+                    return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST, "父级类目不存在~");
+                }
+
+                CategoryEntity parent = optional.get();
+                if (!Objects.equals(categoryType, parent.getCategoryType())) {
+                    return ResponseDTO.userErrorParam("与父级类目类型不一致");
+                }
+            }
+
+        } else {
+            // 如果没有父类 使用默认父类
+            parentId = NumberUtils.LONG_ZERO;
+        }
+
+        // 校验同父类下 名称是否重复
+        CategoryEntity queryEntity = new CategoryEntity();
+        queryEntity.setParentId(parentId);
+        queryEntity.setCategoryType(categoryType);
+        queryEntity.setCategoryName(categoryEntity.getCategoryName());
+        queryEntity.setDeletedFlag(false);
+        queryEntity = categoryDao.selectOne(queryEntity);
+        if (null != queryEntity) {
+            if (isUpdate) {
+                if (!Objects.equals(queryEntity.getCategoryId(), categoryEntity.getCategoryId())) {
+                    return ResponseDTO.userErrorParam("同级下已存在相同类目~");
+                }
+            } else {
+                return ResponseDTO.userErrorParam("同级下已存在相同类目~");
+            }
+        }
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 查询 类目详情
+     *
+     */
+    public ResponseDTO<CategoryVO> queryDetail(Long categoryId) {
+        Optional<CategoryEntity> optional = categoryQueryService.queryCategory(categoryId);
+        if (!optional.isPresent()) {
+            return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST);
+        }
+        CategoryVO adminVO = BlinkBeanUtil.copy(optional.get(), CategoryVO.class);
+        return ResponseDTO.ok(adminVO);
+    }
+
+    /**
+     * 根据父级id 查询所有子类 返回层级树
+     * 如果父类id 为空 返回所有类目层级
+     *
+     */
+    public ResponseDTO<List<CategoryTreeVO>> queryTree(CategoryTreeQueryForm queryForm) {
+        if (null == queryForm.getParentId()) {
+            if (null == queryForm.getCategoryType()) {
+                return ResponseDTO.userErrorParam("类目类型不能为空");
+            }
+            queryForm.setParentId(NumberUtils.LONG_ZERO);
+        }
+        List<CategoryTreeVO> treeList = categoryCacheManager.queryCategoryTree(queryForm.getParentId(), queryForm.getCategoryType());
+        return ResponseDTO.ok(treeList);
+    }
+
+    /**
+     * 删除类目
+     * 如果有未删除的子类 则无法删除
+     *
+     */
+    public ResponseDTO<String> delete(Long categoryId) {
+        Optional<CategoryEntity> optional = categoryQueryService.queryCategory(categoryId);
+        if (!optional.isPresent()) {
+            return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST);
+        }
+
+        List<Long> categorySubId = categoryQueryService.queryCategorySubId(Lists.newArrayList(categoryId));
+        if (CollectionUtils.isNotEmpty(categorySubId)) {
+            return ResponseDTO.userErrorParam("请先删除子级类目");
+        }
+
+        // 更新数据
+        CategoryEntity categoryEntity = new CategoryEntity();
+        categoryEntity.setCategoryId(categoryId);
+        categoryEntity.setDeletedFlag(true);
+        categoryDao.updateById(categoryEntity);
+
+        // 更新缓存
+        categoryCacheManager.removeCache();
+        return ResponseDTO.ok();
+    }
+
+}

+ 41 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/constant/GoodsStatusEnum.java

@@ -0,0 +1,41 @@
+package com.cloud.sa.admin.module.business.goods.constant;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import com.cloud.sa.base.common.enumeration.BaseEnum;
+
+/**
+ * 商品状态
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ *
+ */
+@AllArgsConstructor
+@Getter
+public enum GoodsStatusEnum implements BaseEnum {
+
+    /**
+     * 1 预约中
+     */
+    APPOINTMENT(1, "预约中"),
+
+    /**
+     * 2 售卖
+     */
+    SELL(2, "售卖中"),
+
+    /**
+     * 3 售罄
+     */
+    SELL_OUT(3, "售罄"),
+
+
+    ;
+
+    private final Integer value;
+
+    private final String desc;
+}

+ 93 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/controller/GoodsController.java

@@ -0,0 +1,93 @@
+package com.cloud.sa.admin.module.business.goods.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.cloud.sa.admin.constant.AdminSwaggerTagConst;
+import com.cloud.sa.admin.module.business.goods.domain.form.GoodsAddForm;
+import com.cloud.sa.admin.module.business.goods.domain.form.GoodsQueryForm;
+import com.cloud.sa.admin.module.business.goods.domain.form.GoodsUpdateForm;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import com.cloud.sa.admin.module.business.goods.domain.vo.GoodsExcelVO;
+import com.cloud.sa.admin.module.business.goods.domain.vo.GoodsVO;
+import com.cloud.sa.admin.module.business.goods.service.GoodsService;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.domain.ValidateList;
+import com.cloud.sa.base.common.util.BlinkExcelUtil;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 商品业务
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ * 
+ */
+@RestController
+@Tag(name = AdminSwaggerTagConst.Business.MANAGER_GOODS)
+public class GoodsController {
+
+    @Resource
+    private GoodsService goodsService;
+
+    @Operation(summary = "分页查询 @author admin")
+    @PostMapping("/goods/query")
+    @SaCheckPermission("goods:query")
+    public ResponseDTO<PageResult<GoodsVO>> query(@RequestBody @Valid GoodsQueryForm queryForm) {
+        return goodsService.query(queryForm);
+    }
+
+    @Operation(summary = "添加商品 @author admin")
+    @PostMapping("/goods/add")
+    @SaCheckPermission("goods:add")
+    public ResponseDTO<String> add(@RequestBody @Valid GoodsAddForm addForm) {
+        return goodsService.add(addForm);
+    }
+
+    @Operation(summary = "更新商品 @author admin")
+    @PostMapping("/goods/update")
+    @SaCheckPermission("goods:update")
+    public ResponseDTO<String> update(@RequestBody @Valid GoodsUpdateForm updateForm) {
+        return goodsService.update(updateForm);
+    }
+
+    @Operation(summary = "删除 @author admin")
+    @GetMapping("/goods/delete/{goodsId}")
+    @SaCheckPermission("goods:delete")
+    public ResponseDTO<String> delete(@PathVariable Long goodsId) {
+        return goodsService.delete(goodsId);
+    }
+
+    @Operation(summary = "批量 @author admin")
+    @PostMapping("/goods/batchDelete")
+    @SaCheckPermission("goods:batchDelete")
+    public ResponseDTO<String> batchDelete(@RequestBody @Valid ValidateList<Long> idList) {
+        return goodsService.batchDelete(idList);
+    }
+
+    // --------------- 导出和导入 -------------------
+
+    @Operation(summary = "导入 @author admin")
+    @PostMapping("/goods/importGoods")
+    @SaCheckPermission("goods:importGoods")
+    public ResponseDTO<String> importGoods(@RequestParam MultipartFile file) {
+        return goodsService.importGoods(file);
+    }
+
+    @Operation(summary = "导出 @author admin")
+    @GetMapping("/goods/exportGoods")
+    @SaCheckPermission("goods:exportGoods")
+    public void exportGoods(HttpServletResponse response) throws IOException {
+        List<GoodsExcelVO> goodsList = goodsService.getAllGoods();
+        BlinkExcelUtil.exportExcel(response,"商品列表.xlsx","商品",GoodsExcelVO.class, goodsList);
+    }
+
+}

+ 37 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/dao/GoodsDao.java

@@ -0,0 +1,37 @@
+package com.cloud.sa.admin.module.business.goods.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.goods.domain.entity.GoodsEntity;
+import com.cloud.sa.admin.module.business.goods.domain.form.GoodsQueryForm;
+import com.cloud.sa.admin.module.business.goods.domain.vo.GoodsVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 商品
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ *
+ */
+@Mapper
+@Component
+public interface GoodsDao extends BaseMapper<GoodsEntity> {
+
+    /**
+     * 分页 查询商品
+     *
+     */
+    List<GoodsVO> query(Page page, @Param("query") GoodsQueryForm query);
+
+    /**
+     * 批量更新删除状态
+     */
+
+    void batchUpdateDeleted(@Param("goodsIdList")List<Long> goodsIdList,@Param("deletedFlag")Boolean deletedFlag);
+}

+ 70 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/entity/GoodsEntity.java

@@ -0,0 +1,70 @@
+package com.cloud.sa.admin.module.business.goods.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 商品 实体类
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ *
+ */
+@Data
+@TableName("t_goods")
+public class GoodsEntity {
+
+    @TableId(type = IdType.AUTO)
+    private Long goodsId;
+
+    /**
+     *  商品状态:[1:预约中,2:售卖中,3:售罄]
+     */
+    private Integer goodsStatus;
+
+    /**
+     * 商品分类
+     */
+    private Long categoryId;
+
+    /**
+     * 商品名称
+     */
+    private String goodsName;
+
+    /**
+     * 产地
+     */
+    private String place;
+
+    /**
+     * 商品价格
+     */
+    private BigDecimal price;
+
+
+    /**
+     * 上架状态
+     */
+    private Boolean shelvesFlag;
+
+    /**
+     * 删除状态
+     */
+    private Boolean deletedFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    private LocalDateTime updateTime;
+
+    private LocalDateTime createTime;
+}

+ 55 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/form/GoodsAddForm.java

@@ -0,0 +1,55 @@
+package com.cloud.sa.admin.module.business.goods.domain.form;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.admin.module.business.goods.constant.GoodsStatusEnum;
+import com.cloud.sa.base.common.json.deserializer.DictValueVoDeserializer;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+import com.cloud.sa.base.common.validator.enumeration.CheckEnum;
+
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+/**
+ * 商品 添加表单
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ *
+ */
+@Data
+public class GoodsAddForm {
+
+    @Schema(description = "商品分类")
+    @NotNull(message = "商品分类不能为空")
+    private Long categoryId;
+
+    @Schema(description = "商品名称")
+    @NotBlank(message = "商品名称不能为空")
+    private String goodsName;
+
+    @SchemaEnum(GoodsStatusEnum.class)
+    @CheckEnum(message = "商品状态错误", value = GoodsStatusEnum.class, required = true)
+    private Integer goodsStatus;
+
+    @Schema(description = "产地")
+    @NotBlank(message = "产地 不能为空 ")
+    @JsonDeserialize(using = DictValueVoDeserializer.class)
+    private String place;
+
+    @Schema(description = "商品价格")
+    @NotNull(message = "商品价格不能为空")
+    @DecimalMin(value = "0", message = "商品价格最低0")
+    private BigDecimal price;
+
+    @Schema(description = "上架状态")
+    @NotNull(message = "上架状态不能为空")
+    private Boolean shelvesFlag;
+
+    @Schema(description = "备注|可选")
+    private String remark;
+}

+ 36 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/form/GoodsImportForm.java

@@ -0,0 +1,36 @@
+package com.cloud.sa.admin.module.business.goods.domain.form;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 商品 导入表单
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ * 
+ */
+@Data
+public class GoodsImportForm {
+
+    @ExcelProperty("商品分类")
+    private String categoryName;
+
+    @ExcelProperty("商品名称")
+    private String goodsName;
+
+    @ExcelProperty("商品状态错误")
+    private String goodsStatus;
+
+    @ExcelProperty("产地")
+    private String place;
+
+    @ExcelProperty("商品价格")
+    private BigDecimal price;
+
+    @ExcelProperty("备注")
+    private String remark;
+}

+ 44 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/form/GoodsQueryForm.java

@@ -0,0 +1,44 @@
+package com.cloud.sa.admin.module.business.goods.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.admin.module.business.goods.constant.GoodsStatusEnum;
+import com.cloud.sa.base.common.domain.PageParam;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+import com.cloud.sa.base.common.validator.enumeration.CheckEnum;
+import org.hibernate.validator.constraints.Length;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.cloud.sa.base.common.json.deserializer.DictValueVoDeserializer;
+
+/**
+ * 商品 分页查询
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ *
+ */
+@Data
+public class GoodsQueryForm extends PageParam {
+
+    @Schema(description = "商品分类")
+    private Integer categoryId;
+
+    @Schema(description = "搜索词")
+    @Length(max = 30, message = "搜索词最多30字符")
+    private String searchWord;
+
+    @SchemaEnum(GoodsStatusEnum.class)
+    @CheckEnum(message = "商品状态错误", value = GoodsStatusEnum.class, required = false)
+    private Integer goodsStatus;
+
+    @Schema(description = "产地")
+    @JsonDeserialize(using = DictValueVoDeserializer.class)
+    private String place;
+
+    @Schema(description = "上架状态")
+    private Boolean shelvesFlag;
+
+    @Schema(hidden = true)
+    private Boolean deletedFlag;
+}

+ 22 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/form/GoodsUpdateForm.java

@@ -0,0 +1,22 @@
+package com.cloud.sa.admin.module.business.goods.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 商品 更新表单
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ *
+ */
+@Data
+public class GoodsUpdateForm extends GoodsAddForm {
+
+    @Schema(description = "商品id")
+    @NotNull(message = "商品id不能为空")
+    private Long goodsId;
+}

+ 42 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/vo/GoodsExcelVO.java

@@ -0,0 +1,42 @@
+package com.cloud.sa.admin.module.business.goods.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+/**
+ * excel商品
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ * 
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class GoodsExcelVO {
+
+    @ExcelProperty("商品分类")
+    private String categoryName;
+
+    @ExcelProperty("商品名称")
+    private String goodsName;
+
+    @ExcelProperty("商品状态错误")
+    private String goodsStatus;
+
+    @ExcelProperty("产地")
+    private String place;
+
+    @ExcelProperty("商品价格")
+    private BigDecimal price;
+
+    @ExcelProperty("备注")
+    private String remark;
+}

+ 55 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/domain/vo/GoodsVO.java

@@ -0,0 +1,55 @@
+package com.cloud.sa.admin.module.business.goods.domain.vo;
+
+import com.cloud.sa.admin.module.business.goods.constant.GoodsStatusEnum;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.json.serializer.DictValueVoSerializer;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 商品
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ * 
+ */
+@Data
+public class GoodsVO  {
+
+    @Schema(description = "商品分类")
+    private Long categoryId;
+
+    @Schema(description = "商品名称")
+    private String goodsName;
+
+    @SchemaEnum(GoodsStatusEnum.class)
+    private Integer goodsStatus;
+
+    @Schema(description = "产地")
+    @JsonSerialize(using = DictValueVoSerializer.class)
+    private String place;
+
+    @Schema(description = "商品价格")
+    private BigDecimal price;
+
+    @Schema(description = "上架状态")
+    private Boolean shelvesFlag;
+
+    @Schema(description = "备注|可选")
+    private String remark;
+
+    @Schema(description = "商品id")
+    private Long goodsId;
+
+    @Schema(description = "商品分类")
+    private String categoryName;
+
+    private LocalDateTime updateTime;
+
+    private LocalDateTime createTime;
+}

+ 210 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/goods/service/GoodsService.java

@@ -0,0 +1,210 @@
+package com.cloud.sa.admin.module.business.goods.service;
+
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.category.constant.CategoryTypeEnum;
+import com.cloud.sa.admin.module.business.category.domain.entity.CategoryEntity;
+import com.cloud.sa.admin.module.business.category.service.CategoryQueryService;
+import com.cloud.sa.admin.module.business.goods.constant.GoodsStatusEnum;
+import com.cloud.sa.admin.module.business.goods.domain.form.GoodsAddForm;
+import com.cloud.sa.admin.module.business.goods.domain.form.GoodsImportForm;
+import com.cloud.sa.admin.module.business.goods.domain.form.GoodsQueryForm;
+import com.cloud.sa.admin.module.business.goods.domain.form.GoodsUpdateForm;
+import lombok.extern.slf4j.Slf4j;
+import com.cloud.sa.admin.module.business.goods.dao.GoodsDao;
+import com.cloud.sa.admin.module.business.goods.domain.entity.GoodsEntity;
+import com.cloud.sa.admin.module.business.goods.domain.vo.GoodsExcelVO;
+import com.cloud.sa.admin.module.business.goods.domain.vo.GoodsVO;
+import com.cloud.sa.base.common.code.UserErrorCode;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.exception.BusinessException;
+import com.cloud.sa.base.common.util.BlinkBeanUtil;
+import com.cloud.sa.base.common.util.BlinkEnumUtil;
+import com.cloud.sa.base.common.util.BlinkPageUtil;
+import com.cloud.sa.base.module.support.datatracer.constant.DataTracerTypeEnum;
+import com.cloud.sa.base.module.support.datatracer.service.DataTracerService;
+import com.cloud.sa.base.module.support.dict.service.DictCacheService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 商品
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-10-25 20:26:54
+
+ * 
+ */
+@Service
+@Slf4j
+public class GoodsService {
+
+    @Resource
+    private GoodsDao goodsDao;
+
+    @Resource
+    private CategoryQueryService categoryQueryService;
+
+    @Resource
+    private DataTracerService dataTracerService;
+
+    @Resource
+    private DictCacheService dictCacheService;
+
+    /**
+     * 添加商品
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> add(GoodsAddForm addForm) {
+        // 商品校验
+        ResponseDTO<String> res = this.checkGoods(addForm);
+        if (!res.getOk()) {
+            return res;
+        }
+        GoodsEntity goodsEntity = BlinkBeanUtil.copy(addForm, GoodsEntity.class);
+        goodsEntity.setDeletedFlag(Boolean.FALSE);
+        goodsDao.insert(goodsEntity);
+        dataTracerService.insert(goodsEntity.getGoodsId(), DataTracerTypeEnum.GOODS);
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 更新商品
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> update(GoodsUpdateForm updateForm) {
+        // 商品校验
+        ResponseDTO<String> res = this.checkGoods(updateForm);
+        if (!res.getOk()) {
+            return res;
+        }
+        GoodsEntity originEntity = goodsDao.selectById(updateForm.getGoodsId());
+        GoodsEntity goodsEntity = BlinkBeanUtil.copy(updateForm, GoodsEntity.class);
+        goodsDao.updateById(goodsEntity);
+        dataTracerService.update(updateForm.getGoodsId(), DataTracerTypeEnum.GOODS, originEntity, goodsEntity);
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 添加/更新 商品校验
+     */
+    private ResponseDTO<String> checkGoods(GoodsAddForm addForm) {
+        // 校验类目id
+        Long categoryId = addForm.getCategoryId();
+        Optional<CategoryEntity> optional = categoryQueryService.queryCategory(categoryId);
+        if (!optional.isPresent() || !CategoryTypeEnum.GOODS.equalsValue(optional.get().getCategoryType())) {
+            return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST, "商品类目不存在~");
+        }
+
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 删除
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> delete(Long goodsId) {
+        GoodsEntity goodsEntity = goodsDao.selectById(goodsId);
+        if (goodsEntity == null) {
+            return ResponseDTO.userErrorParam("商品不存在");
+        }
+
+        if (!goodsEntity.getGoodsStatus().equals(GoodsStatusEnum.SELL_OUT.getValue())) {
+            return ResponseDTO.userErrorParam("只有售罄的商品才可以删除");
+        }
+
+        batchDelete(Collections.singletonList(goodsId));
+        dataTracerService.batchDelete(Collections.singletonList(goodsId), DataTracerTypeEnum.GOODS);
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 批量删除
+     */
+    public ResponseDTO<String> batchDelete(List<Long> goodsIdList) {
+        if (CollectionUtils.isEmpty(goodsIdList)) {
+            return ResponseDTO.ok();
+        }
+
+        goodsDao.batchUpdateDeleted(goodsIdList, Boolean.TRUE);
+        return ResponseDTO.ok();
+    }
+
+
+    /**
+     * 分页查询
+     */
+    public ResponseDTO<PageResult<GoodsVO>> query(GoodsQueryForm queryForm) {
+        queryForm.setDeletedFlag(false);
+        Page<?> page = BlinkPageUtil.convert2PageQuery(queryForm);
+        List<GoodsVO> list = goodsDao.query(page, queryForm);
+        PageResult<GoodsVO> pageResult = BlinkPageUtil.convert2PageResult(page, list);
+        if (pageResult.getEmptyFlag()) {
+            return ResponseDTO.ok(pageResult);
+        }
+        // 查询分类名称
+        List<Long> categoryIdList = list.stream().map(GoodsVO::getCategoryId).distinct().collect(Collectors.toList());
+        Map<Long, CategoryEntity> categoryMap = categoryQueryService.queryCategoryList(categoryIdList);
+        list.forEach(e -> {
+            CategoryEntity categoryEntity = categoryMap.get(e.getCategoryId());
+            if (categoryEntity != null) {
+                e.setCategoryName(categoryEntity.getCategoryName());
+            }
+        });
+        return ResponseDTO.ok(pageResult);
+    }
+
+    /**
+     * 商品导入
+     *
+     * @param file 上传文件
+     * @return 结果
+     */
+    public ResponseDTO<String> importGoods(MultipartFile file) {
+        List<GoodsImportForm> dataList;
+        try {
+            dataList = EasyExcel.read(file.getInputStream()).head(GoodsImportForm.class)
+                    .sheet()
+                    .doReadSync();
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            throw new BusinessException("数据格式存在问题,无法读取");
+        }
+
+        if (CollectionUtils.isEmpty(dataList)) {
+            return ResponseDTO.userErrorParam("数据为空");
+        }
+
+        return ResponseDTO.okMsg("成功导入" + dataList.size() + "条,具体数据为:" + JSON.toJSONString(dataList));
+    }
+
+    /**
+     * 商品导出
+     */
+    public List<GoodsExcelVO> getAllGoods() {
+        List<GoodsEntity> goodsEntityList = goodsDao.selectList(null);
+        return goodsEntityList.stream()
+                .map(e ->
+                        GoodsExcelVO.builder()
+                                .goodsStatus(BlinkEnumUtil.getEnumDescByValue(e.getGoodsStatus(), GoodsStatusEnum.class))
+                                .categoryName(categoryQueryService.queryCategoryName(e.getCategoryId()))
+                                //.place(dictCacheService.selectValueNameByValueCode(e.getPlace()))
+                                .place(Arrays.stream(e.getPlace().split(",")).map(code -> dictCacheService.selectValueNameByValueCode(code)).collect(Collectors.joining(",")))
+                                .price(e.getPrice())
+                                .goodsName(e.getGoodsName())
+                                .remark(e.getRemark())
+                                .build()
+                )
+                .collect(Collectors.toList());
+
+    }
+}

+ 73 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/BankController.java

@@ -0,0 +1,73 @@
+package com.cloud.sa.admin.module.business.oa.bank;
+
+import com.cloud.sa.admin.constant.AdminSwaggerTagConst;
+import com.cloud.sa.admin.module.business.oa.bank.domain.BankCreateForm;
+import com.cloud.sa.admin.module.business.oa.bank.domain.BankQueryForm;
+import com.cloud.sa.admin.module.business.oa.bank.domain.BankUpdateForm;
+import com.cloud.sa.admin.module.business.oa.bank.domain.BankVO;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.RequestUser;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.util.BlinkRequestUtil;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * OA办公-OA银行信息
+ *
+ * @Author 云畅联:admin
+ * @Date 2022/6/23 21:59:22
+
+ * 
+ */
+@RestController
+@Tag(name = AdminSwaggerTagConst.Business.OA_BANK)
+public class BankController {
+
+    @Resource
+    private BankService bankService;
+
+    @Operation(summary = "分页查询银行信息 @author admin")
+    @PostMapping("/oa/bank/page/query")
+    public ResponseDTO<PageResult<BankVO>> queryByPage(@RequestBody @Valid BankQueryForm queryForm) {
+        return bankService.queryByPage(queryForm);
+    }
+
+    @Operation(summary = "根据企业ID查询银行信息列表 @author admin")
+    @GetMapping("/oa/bank/query/list/{enterpriseId}")
+    public ResponseDTO<List<BankVO>> queryList(@PathVariable Long enterpriseId) {
+        return bankService.queryList(enterpriseId);
+    }
+
+    @Operation(summary = "查询银行信息详情 @author admin")
+    @GetMapping("/oa/bank/get/{bankId}")
+    public ResponseDTO<BankVO> getDetail(@PathVariable Long bankId) {
+        return bankService.getDetail(bankId);
+    }
+
+    @Operation(summary = "新建银行信息 @author admin")
+    @PostMapping("/oa/bank/create")
+    public ResponseDTO<String> createBank(@RequestBody @Valid BankCreateForm createVO) {
+        RequestUser requestUser = BlinkRequestUtil.getRequestUser();
+        createVO.setCreateUserId(requestUser.getUserId());
+        createVO.setCreateUserName(requestUser.getUserName());
+        return bankService.createBank(createVO);
+    }
+
+    @Operation(summary = "编辑银行信息 @author admin")
+    @PostMapping("/oa/bank/update")
+    public ResponseDTO<String> updateBank(@RequestBody @Valid BankUpdateForm updateVO) {
+        return bankService.updateBank(updateVO);
+    }
+
+    @Operation(summary = "删除银行信息 @author admin")
+    @GetMapping("/oa/bank/delete/{bankId}")
+    public ResponseDTO<String> deleteBank(@PathVariable Long bankId) {
+        return bankService.deleteBank(bankId);
+    }
+}

+ 47 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/BankDao.java

@@ -0,0 +1,47 @@
+package com.cloud.sa.admin.module.business.oa.bank;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.oa.bank.domain.BankEntity;
+import com.cloud.sa.admin.module.business.oa.bank.domain.BankQueryForm;
+import com.cloud.sa.admin.module.business.oa.bank.domain.BankVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * OA办公-OA银行信息
+ *
+ * @Author 云畅联:admin
+ * @Date 2022/6/23 21:59:22
+
+ *
+ */
+@Mapper
+@Component
+public interface BankDao extends BaseMapper<BankEntity> {
+
+    /**
+     * 根据账号查询
+     */
+    BankEntity queryByAccountNumber(@Param("enterpriseId") Long enterpriseId, @Param("accountNumber") String accountNumber, @Param("excludeBankId") Long excludeBankId, @Param("deletedFlag") Boolean deletedFlag);
+
+    /**
+     * 删除银行信息
+     *
+     */
+    void deleteBank(@Param("bankId") Long bankId, @Param("deletedFlag") Boolean deletedFlag);
+
+    /**
+     * 银行信息分页查询
+     *
+     */
+    List<BankVO> queryPage(Page page, @Param("queryForm") BankQueryForm queryForm);
+
+    /**
+     * 查询银行信息详情
+     */
+    BankVO getDetail(@Param("bankId") Long bankId, @Param("deletedFlag") Boolean deletedFlag);
+}

+ 144 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/BankService.java

@@ -0,0 +1,144 @@
+package com.cloud.sa.admin.module.business.oa.bank;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.oa.bank.domain.*;
+import com.cloud.sa.admin.module.business.oa.enterprise.dao.EnterpriseDao;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEntity;
+import lombok.extern.slf4j.Slf4j;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.util.BlinkBeanUtil;
+import com.cloud.sa.base.common.util.BlinkPageUtil;
+import com.cloud.sa.base.module.support.datatracer.constant.DataTracerConst;
+import com.cloud.sa.base.module.support.datatracer.constant.DataTracerTypeEnum;
+import com.cloud.sa.base.module.support.datatracer.service.DataTracerService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * OA办公-OA银行信息
+ *
+ * @Author 云畅联:admin
+ * @Date 2022/6/23 21:59:22
+
+ * 
+ */
+@Service
+@Slf4j
+public class BankService {
+
+    @Resource
+    private BankDao bankDao;
+
+    @Resource
+    private EnterpriseDao enterpriseDao;
+
+    @Resource
+    private DataTracerService dataTracerService;
+
+    /**
+     * 分页查询银行信息
+     */
+    public ResponseDTO<PageResult<BankVO>> queryByPage(BankQueryForm queryForm) {
+        queryForm.setDeletedFlag(Boolean.FALSE);
+        Page<?> page = BlinkPageUtil.convert2PageQuery(queryForm);
+        List<BankVO> bankList = bankDao.queryPage(page, queryForm);
+        PageResult<BankVO> pageResult = BlinkPageUtil.convert2PageResult(page, bankList);
+        return ResponseDTO.ok(pageResult);
+    }
+
+    /**
+     * 根据企业ID查询不分页的银行列表
+     */
+    public ResponseDTO<List<BankVO>> queryList(Long enterpriseId) {
+        BankQueryForm queryForm = new BankQueryForm();
+        queryForm.setEnterpriseId(enterpriseId);
+        queryForm.setDeletedFlag(Boolean.FALSE);
+        List<BankVO> bankList = bankDao.queryPage(null, queryForm);
+        return ResponseDTO.ok(bankList);
+    }
+
+    /**
+     * 查询银行信息详情
+     */
+    public ResponseDTO<BankVO> getDetail(Long bankId) {
+        // 校验银行信息是否存在
+        BankVO bankVO = bankDao.getDetail(bankId, Boolean.FALSE);
+        if (Objects.isNull(bankVO)) {
+            return ResponseDTO.userErrorParam("银行信息不存在");
+        }
+        return ResponseDTO.ok(bankVO);
+    }
+
+    /**
+     * 新建银行信息
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> createBank(BankCreateForm createVO) {
+        Long enterpriseId = createVO.getEnterpriseId();
+        // 校验企业是否存在
+        EnterpriseEntity enterpriseDetail = enterpriseDao.selectById(enterpriseId);
+        if (Objects.isNull(enterpriseDetail) || enterpriseDetail.getDeletedFlag()) {
+            return ResponseDTO.userErrorParam("企业不存在");
+        }
+        // 验证银行信息账号是否重复
+        BankEntity validateBank = bankDao.queryByAccountNumber(enterpriseId, createVO.getAccountNumber(), null, Boolean.FALSE);
+        if (Objects.nonNull(validateBank)) {
+            return ResponseDTO.userErrorParam("银行信息账号重复");
+        }
+        // 数据插入
+        BankEntity insertBank = BlinkBeanUtil.copy(createVO, BankEntity.class);
+        bankDao.insert(insertBank);
+        dataTracerService.addTrace(enterpriseId, DataTracerTypeEnum.OA_ENTERPRISE, "新增银行:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(insertBank));
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 编辑银行信息
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> updateBank(BankUpdateForm updateVO) {
+        Long enterpriseId = updateVO.getEnterpriseId();
+        // 校验企业是否存在
+        EnterpriseEntity enterpriseDetail = enterpriseDao.selectById(enterpriseId);
+        if (Objects.isNull(enterpriseDetail) || enterpriseDetail.getDeletedFlag()) {
+            return ResponseDTO.userErrorParam("企业不存在");
+        }
+        Long bankId = updateVO.getBankId();
+        // 校验银行信息是否存在
+        BankEntity bankDetail = bankDao.selectById(bankId);
+        if (Objects.isNull(bankDetail) || bankDetail.getDeletedFlag()) {
+            return ResponseDTO.userErrorParam("银行信息不存在");
+        }
+        // 验证银行信息账号是否重复
+        BankEntity validateBank = bankDao.queryByAccountNumber(updateVO.getEnterpriseId(), updateVO.getAccountNumber(), bankId, Boolean.FALSE);
+        if (Objects.nonNull(validateBank)) {
+            return ResponseDTO.userErrorParam("银行信息账号重复");
+        }
+        // 数据编辑
+        BankEntity updateBank = BlinkBeanUtil.copy(updateVO, BankEntity.class);
+        bankDao.updateById(updateBank);
+        dataTracerService.addTrace(enterpriseId, DataTracerTypeEnum.OA_ENTERPRISE, "更新银行:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(bankDetail, updateBank));
+        return ResponseDTO.ok();
+    }
+
+
+    /**
+     * 删除银行信息
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> deleteBank(Long bankId) {
+        // 校验银行信息是否存在
+        BankEntity bankDetail = bankDao.selectById(bankId);
+        if (Objects.isNull(bankDetail) || bankDetail.getDeletedFlag()) {
+            return ResponseDTO.userErrorParam("银行信息不存在");
+        }
+        bankDao.deleteBank(bankId, Boolean.TRUE);
+        dataTracerService.addTrace(bankDetail.getEnterpriseId(), DataTracerTypeEnum.OA_ENTERPRISE, "删除银行:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(bankDetail));
+        return ResponseDTO.ok();
+    }
+}

+ 57 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/domain/BankCreateForm.java

@@ -0,0 +1,57 @@
+package com.cloud.sa.admin.module.business.oa.bank.domain;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * OA办公-银行信息新建
+ *
+ * @Author 云畅联:admin
+ * @Date 2022/6/23 21:59:22
+
+ * 
+ */
+@Data
+public class BankCreateForm {
+
+    @Schema(description = "开户银行")
+    @NotBlank(message = "开户银行不能为空")
+    @Length(max = 200, message = "开户银行最多200字符")
+    private String bankName;
+
+    @Schema(description = "账户名称")
+    @NotBlank(message = "账户名称不能为空")
+    @Length(max = 200, message = "账户名称最多200字符")
+    private String accountName;
+
+    @Schema(description = "账号")
+    @NotBlank(message = "账号不能为空")
+    @Length(max = 200, message = "账号最多200字符")
+    private String accountNumber;
+
+    @Schema(description = "备注")
+    @Length(max = 500, message = "备注最多500字符")
+    private String remark;
+
+    @Schema(description = "是否对公")
+    @NotNull(message = "是否对公不能为空")
+    private Boolean businessFlag;
+
+    @Schema(description = "企业")
+    @NotNull(message = "企业不能为空")
+    private Long enterpriseId;
+
+    @Schema(description = "禁用状态")
+    @NotNull(message = "禁用状态不能为空")
+    private Boolean disabledFlag;
+
+    @Schema(hidden = true)
+    private Long createUserId;
+
+    @Schema(hidden = true)
+    private String createUserName;
+}

+ 94 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/domain/BankEntity.java

@@ -0,0 +1,94 @@
+package com.cloud.sa.admin.module.business.oa.bank.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import com.cloud.sa.base.module.support.datatracer.annoation.DataTracerFieldLabel;
+
+import java.time.LocalDateTime;
+
+/**
+ * OA办公-OA银行信息
+ *
+ * @Author 云畅联:admin
+ * @Date 2022/6/23 21:59:22
+
+ *
+ */
+@Data
+@TableName("t_oa_bank")
+public class BankEntity {
+
+    /**
+     * 银行信息ID
+     */
+    @TableId(type = IdType.AUTO)
+    @DataTracerFieldLabel("银行信息ID")
+    private Long bankId;
+
+    /**
+     * 开户银行
+     */
+    @DataTracerFieldLabel("开户银行")
+    private String bankName;
+
+    /**
+     * 账户名称
+     */
+    @DataTracerFieldLabel("账户名称")
+    private String accountName;
+
+    /**
+     * 账号
+     */
+    @DataTracerFieldLabel("账号")
+    private String accountNumber;
+
+    /**
+     * 备注
+     */
+    @DataTracerFieldLabel("备注")
+    private String remark;
+
+    /**
+     * 是否对公
+     */
+    @DataTracerFieldLabel("是否对公")
+    private Boolean businessFlag;
+
+    /**
+     * 企业ID
+     */
+    private Long enterpriseId;
+
+    /**
+     * 禁用状态
+     */
+    @DataTracerFieldLabel("禁用状态")
+    private Boolean disabledFlag;
+
+    /**
+     * 删除状态
+     */
+    private Boolean deletedFlag;
+
+    /**
+     * 创建人ID
+     */
+    private Long createUserId;
+
+    /**
+     * 创建人ID
+     */
+    private String createUserName;
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 39 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/domain/BankQueryForm.java

@@ -0,0 +1,39 @@
+package com.cloud.sa.admin.module.business.oa.bank.domain;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.domain.PageParam;
+import org.hibernate.validator.constraints.Length;
+
+import java.time.LocalDate;
+
+/**
+ * OA办公-OA银行信息查询
+ *
+ * @Author 云畅联:admin
+ * @Date 2022/6/23 21:59:22
+
+ * 
+ */
+@Data
+public class BankQueryForm extends PageParam {
+
+    @Schema(description = "企业ID")
+    private Long enterpriseId;
+
+    @Schema(description = "关键字")
+    @Length(max = 200, message = "关键字最多200字符")
+    private String keywords;
+
+    @Schema(description = "开始时间")
+    private LocalDate startTime;
+
+    @Schema(description = "结束时间")
+    private LocalDate endTime;
+
+    @Schema(description = "禁用状态")
+    private Boolean disabledFlag;
+
+    @Schema(description = "删除状态", hidden = true)
+    private Boolean deletedFlag;
+}

+ 22 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/domain/BankUpdateForm.java

@@ -0,0 +1,22 @@
+package com.cloud.sa.admin.module.business.oa.bank.domain;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * OA办公-银行信息更新
+ *
+ * @Author 云畅联:admin
+ * @Date 2022/6/23 21:59:22
+
+ *
+ */
+@Data
+public class BankUpdateForm extends BankCreateForm {
+
+    @Schema(description = "银行信息ID")
+    @NotNull(message = "银行信息ID不能为空")
+    private Long bankId;
+}

+ 57 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/bank/domain/BankVO.java

@@ -0,0 +1,57 @@
+package com.cloud.sa.admin.module.business.oa.bank.domain;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * OA办公-OA银行信息
+ *
+ * @Author 云畅联:admin
+ * @Date 2022/6/23 21:59:22
+
+ *
+ */
+@Data
+public class BankVO {
+
+    @Schema(description = "银行信息ID")
+    private Long bankId;
+
+    @Schema(description = "开户银行")
+    private String bankName;
+
+    @Schema(description = "账户名称")
+    private String accountName;
+
+    @Schema(description = "账号")
+    private String accountNumber;
+
+    @Schema(description = "备注")
+    private String remark;
+
+    @Schema(description = "是否对公")
+    private Boolean businessFlag;
+
+    @Schema(description = "企业ID")
+    private Long enterpriseId;
+
+    @Schema(description = "企业名称")
+    private String enterpriseName;
+
+    @Schema(description = "禁用状态")
+    private Boolean disabledFlag;
+
+    @Schema(description = "创建人ID")
+    private Long createUserId;
+
+    @Schema(description = "创建人名称")
+    private String createUserName;
+
+    @Schema(description = "创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "更新时间")
+    private LocalDateTime updateTime;
+}

+ 133 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/EnterpriseController.java

@@ -0,0 +1,133 @@
+package com.cloud.sa.admin.module.business.oa.enterprise;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.cloud.sa.admin.constant.AdminSwaggerTagConst;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.form.*;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEmployeeVO;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseListVO;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO;
+import com.cloud.sa.base.common.util.*;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+import com.cloud.sa.admin.util.AdminRequestUtil;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.RequestUser;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.module.support.operatelog.annotation.OperateLog;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 企业
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ *
+ */
+@Slf4j
+@RestController
+@Tag(name = AdminSwaggerTagConst.Business.OA_ENTERPRISE)
+@OperateLog
+public class EnterpriseController {
+
+    @Resource
+    private EnterpriseService enterpriseService;
+
+    @Operation(summary = "分页查询企业模块 @author admin")
+    @PostMapping("/oa/enterprise/page/query")
+    @SaCheckPermission("oa:enterprise:query")
+    public ResponseDTO<PageResult<EnterpriseVO>> queryByPage(@RequestBody @Valid EnterpriseQueryForm queryForm) {
+        return enterpriseService.queryByPage(queryForm);
+    }
+
+    @Operation(summary = "导出企业信息 @author admin")
+    @PostMapping("/oa/enterprise/exportExcel")
+    public void exportExcel(@RequestBody @Valid EnterpriseQueryForm queryForm, HttpServletResponse response) throws IOException {
+        List<EnterpriseExcelVO> data = enterpriseService.getExcelExportData(queryForm);
+        if (CollectionUtils.isEmpty(data)) {
+            BlinkResponseUtil.write(response, ResponseDTO.userErrorParam("暂无数据"));
+            return;
+        }
+
+        String watermark = AdminRequestUtil.getRequestUser().getActualName();
+        watermark += BlinkLocalDateUtil.format(LocalDateTime.now(), BlinkDateFormatterEnum.YMD_HMS);
+
+        BlinkExcelUtil.exportExcelWithWatermark(response,"企业基本信息.xlsx","企业信息",EnterpriseExcelVO.class,data,watermark);
+
+    }
+
+    @Operation(summary = "查询企业详情 @author admin")
+    @GetMapping("/oa/enterprise/get/{enterpriseId}")
+    @SaCheckPermission("oa:enterprise:detail")
+    public ResponseDTO<EnterpriseVO> getDetail(@PathVariable Long enterpriseId) {
+        return ResponseDTO.ok(enterpriseService.getDetail(enterpriseId));
+    }
+
+    @Operation(summary = "新建企业 @author admin")
+    @PostMapping("/oa/enterprise/create")
+    @SaCheckPermission("oa:enterprise:add")
+    public ResponseDTO<String> createEnterprise(@RequestBody @Valid EnterpriseCreateForm createVO) {
+        RequestUser requestUser = BlinkRequestUtil.getRequestUser();
+        createVO.setCreateUserId(requestUser.getUserId());
+        createVO.setCreateUserName(requestUser.getUserName());
+        return enterpriseService.createEnterprise(createVO);
+    }
+
+    @Operation(summary = "编辑企业 @author admin")
+    @PostMapping("/oa/enterprise/update")
+    @SaCheckPermission("oa:enterprise:update")
+    public ResponseDTO<String> updateEnterprise(@RequestBody @Valid EnterpriseUpdateForm updateVO) {
+        return enterpriseService.updateEnterprise(updateVO);
+    }
+
+    @Operation(summary = "删除企业 @author admin")
+    @GetMapping("/oa/enterprise/delete/{enterpriseId}")
+    @SaCheckPermission("oa:enterprise:delete")
+    public ResponseDTO<String> deleteEnterprise(@PathVariable Long enterpriseId) {
+        return enterpriseService.deleteEnterprise(enterpriseId);
+    }
+
+    @Operation(summary = "按照类型查询企业 @author admin")
+    @GetMapping("/oa/enterprise/query/list")
+    public ResponseDTO<List<EnterpriseListVO>> queryList(@RequestParam(value = "type", required = false) Integer type) {
+        return enterpriseService.queryList(type);
+    }
+
+
+    @Operation(summary = "企业添加员工 @author admin")
+    @PostMapping("/oa/enterprise/employee/add")
+    @SaCheckPermission("oa:enterprise:addEmployee")
+    public ResponseDTO<String> addEmployee(@RequestBody @Valid EnterpriseEmployeeForm enterpriseEmployeeForm) {
+        return enterpriseService.addEmployee(enterpriseEmployeeForm);
+    }
+
+    @Operation(summary = "查询企业全部员工 @author admin")
+    @PostMapping("/oa/enterprise/employee/list")
+    public ResponseDTO<List<EnterpriseEmployeeVO>> employeeList(@RequestBody @Valid List<Long> enterpriseIdList) {
+        return ResponseDTO.ok(enterpriseService.employeeList(enterpriseIdList));
+    }
+
+    @Operation(summary = "分页查询企业员工 @author admin")
+    @PostMapping("/oa/enterprise/employee/queryPage")
+    public ResponseDTO<PageResult<EnterpriseEmployeeVO>> queryPageEmployeeList(@RequestBody @Valid EnterpriseEmployeeQueryForm queryForm) {
+        return ResponseDTO.ok(enterpriseService.queryPageEmployeeList(queryForm));
+    }
+
+
+    @Operation(summary = "企业删除员工 @author admin")
+    @PostMapping("/oa/enterprise/employee/delete")
+    @SaCheckPermission("oa:enterprise:deleteEmployee")
+    public ResponseDTO<String> deleteEmployee(@RequestBody @Valid EnterpriseEmployeeForm enterpriseEmployeeForm) {
+        return enterpriseService.deleteEmployee(enterpriseEmployeeForm);
+    }
+}

+ 18 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/EnterpriseEmployeeManager.java

@@ -0,0 +1,18 @@
+package com.cloud.sa.admin.module.business.oa.enterprise;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEmployeeEntity;
+import com.cloud.sa.admin.module.business.oa.enterprise.dao.EnterpriseEmployeeDao;
+import org.springframework.stereotype.Service;
+
+/**
+ * 企业员工关系 manager
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ * 
+ */
+@Service
+public class EnterpriseEmployeeManager extends ServiceImpl<EnterpriseEmployeeDao, EnterpriseEmployeeEntity> {
+}

+ 237 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/EnterpriseService.java

@@ -0,0 +1,237 @@
+package com.cloud.sa.admin.module.business.oa.enterprise;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEmployeeEntity;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEntity;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.form.*;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEmployeeVO;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseListVO;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO;
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import com.cloud.sa.admin.module.business.oa.enterprise.dao.EnterpriseDao;
+import com.cloud.sa.admin.module.business.oa.enterprise.dao.EnterpriseEmployeeDao;
+import com.cloud.sa.admin.module.system.department.service.DepartmentService;
+import com.cloud.sa.base.common.code.UserErrorCode;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.util.BlinkBeanUtil;
+import com.cloud.sa.base.common.util.BlinkPageUtil;
+import com.cloud.sa.base.module.support.datatracer.constant.DataTracerTypeEnum;
+import com.cloud.sa.base.module.support.datatracer.domain.form.DataTracerForm;
+import com.cloud.sa.base.module.support.datatracer.service.DataTracerService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * 企业
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ * 
+ */
+@Service
+@Slf4j
+public class EnterpriseService {
+
+    @Resource
+    private EnterpriseDao enterpriseDao;
+
+    @Resource
+    private EnterpriseEmployeeDao enterpriseEmployeeDao;
+
+    @Resource
+    private EnterpriseEmployeeManager enterpriseEmployeeManager;
+
+    @Resource
+    private DataTracerService dataTracerService;
+
+    @Resource
+    private DepartmentService departmentService;
+
+    /**
+     * 分页查询企业模块
+     *
+     */
+    public ResponseDTO<PageResult<EnterpriseVO>> queryByPage(EnterpriseQueryForm queryForm) {
+        queryForm.setDeletedFlag(Boolean.FALSE);
+        Page<?> page = BlinkPageUtil.convert2PageQuery(queryForm);
+        List<EnterpriseVO> enterpriseList = enterpriseDao.queryPage(page, queryForm);
+        PageResult<EnterpriseVO> pageResult = BlinkPageUtil.convert2PageResult(page, enterpriseList);
+        return ResponseDTO.ok(pageResult);
+    }
+
+    /**
+     * 获取导出数据
+     */
+    public List<EnterpriseExcelVO> getExcelExportData(EnterpriseQueryForm queryForm) {
+        queryForm.setDeletedFlag(false);
+        return enterpriseDao.selectExcelExportData(queryForm);
+    }
+
+    /**
+     * 查询企业详情
+     *
+     */
+    public EnterpriseVO getDetail(Long enterpriseId) {
+        return enterpriseDao.getDetail(enterpriseId, Boolean.FALSE);
+    }
+
+    /**
+     * 新建企业
+     *
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> createEnterprise(EnterpriseCreateForm createVO) {
+        // 验证企业名称是否重复
+        EnterpriseEntity validateEnterprise = enterpriseDao.queryByEnterpriseName(createVO.getEnterpriseName(), null, Boolean.FALSE);
+        if (Objects.nonNull(validateEnterprise)) {
+            return ResponseDTO.userErrorParam("企业名称重复");
+        }
+        // 数据插入
+        EnterpriseEntity insertEnterprise = BlinkBeanUtil.copy(createVO, EnterpriseEntity.class);
+        enterpriseDao.insert(insertEnterprise);
+        dataTracerService.insert(insertEnterprise.getEnterpriseId(), DataTracerTypeEnum.OA_ENTERPRISE);
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 编辑企业
+     *
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> updateEnterprise(EnterpriseUpdateForm updateVO) {
+        Long enterpriseId = updateVO.getEnterpriseId();
+        // 校验企业是否存在
+        EnterpriseEntity enterpriseDetail = enterpriseDao.selectById(enterpriseId);
+        if (Objects.isNull(enterpriseDetail) || enterpriseDetail.getDeletedFlag()) {
+            return ResponseDTO.userErrorParam("企业不存在");
+        }
+        // 验证企业名称是否重复
+        EnterpriseEntity validateEnterprise = enterpriseDao.queryByEnterpriseName(updateVO.getEnterpriseName(), enterpriseId, Boolean.FALSE);
+        if (Objects.nonNull(validateEnterprise)) {
+            return ResponseDTO.userErrorParam("企业名称重复");
+        }
+        // 数据编辑
+        EnterpriseEntity updateEntity = BlinkBeanUtil.copy(enterpriseDetail, EnterpriseEntity.class);
+        BlinkBeanUtil.copyProperties(updateVO, updateEntity);
+        enterpriseDao.updateById(updateEntity);
+
+        //变更记录
+        DataTracerForm dataTracerForm = DataTracerForm.builder()
+                .dataId(updateVO.getEnterpriseId())
+                .type(DataTracerTypeEnum.OA_ENTERPRISE)
+                .content("修改企业信息")
+                .diffOld(dataTracerService.getChangeContent(enterpriseDetail))
+                .diffNew(dataTracerService.getChangeContent(updateEntity))
+                .build();
+
+        dataTracerService.addTrace(dataTracerForm);
+        return ResponseDTO.ok();
+    }
+
+
+    /**
+     * 删除企业
+     *
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> deleteEnterprise(Long enterpriseId) {
+        // 校验企业是否存在
+        EnterpriseEntity enterpriseDetail = enterpriseDao.selectById(enterpriseId);
+        if (Objects.isNull(enterpriseDetail) || enterpriseDetail.getDeletedFlag()) {
+            return ResponseDTO.userErrorParam("企业不存在");
+        }
+        enterpriseDao.deleteEnterprise(enterpriseId, Boolean.TRUE);
+        dataTracerService.delete(enterpriseId, DataTracerTypeEnum.OA_ENTERPRISE);
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 企业列表查询
+     */
+    public ResponseDTO<List<EnterpriseListVO>> queryList(Integer type) {
+        List<EnterpriseListVO> enterpriseList = enterpriseDao.queryList(type, Boolean.FALSE, Boolean.FALSE);
+        return ResponseDTO.ok(enterpriseList);
+    }
+
+    //----------------------------------------- 以下为员工相关--------------------------------------------
+
+    /**
+     * 企业添加员工
+     *
+     */
+    public synchronized ResponseDTO<String> addEmployee(EnterpriseEmployeeForm enterpriseEmployeeForm) {
+        Long enterpriseId = enterpriseEmployeeForm.getEnterpriseId();
+        EnterpriseEntity enterpriseEntity = enterpriseDao.selectById(enterpriseId);
+        if (enterpriseEntity == null || enterpriseEntity.getDeletedFlag()) {
+            return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST);
+        }
+        //过滤掉已存在的员工
+        List<Long> waitAddEmployeeIdList = enterpriseEmployeeForm.getEmployeeIdList();
+        List<EnterpriseEmployeeEntity> enterpriseEmployeeEntityList = enterpriseEmployeeDao.selectByEnterpriseAndEmployeeIdList(enterpriseId, waitAddEmployeeIdList);
+        if (CollectionUtils.isNotEmpty(enterpriseEmployeeEntityList)) {
+            List<Long> existEmployeeIdList = enterpriseEmployeeEntityList.stream().map(EnterpriseEmployeeEntity::getEmployeeId).collect(Collectors.toList());
+            waitAddEmployeeIdList = waitAddEmployeeIdList.stream().filter(e -> !existEmployeeIdList.contains(e)).collect(Collectors.toList());
+        }
+        if (CollectionUtils.isEmpty(waitAddEmployeeIdList)) {
+            return ResponseDTO.ok();
+        }
+        List<EnterpriseEmployeeEntity> batchAddList = Lists.newArrayList();
+        for (Long employeeId : waitAddEmployeeIdList) {
+            EnterpriseEmployeeEntity enterpriseEmployeeEntity = new EnterpriseEmployeeEntity();
+            enterpriseEmployeeEntity.setEnterpriseId(enterpriseId);
+            enterpriseEmployeeEntity.setEmployeeId(employeeId);
+            batchAddList.add(enterpriseEmployeeEntity);
+        }
+        enterpriseEmployeeManager.saveBatch(batchAddList);
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 企业删除员工
+     *
+     */
+    public synchronized ResponseDTO<String> deleteEmployee(EnterpriseEmployeeForm enterpriseEmployeeForm) {
+        Long enterpriseId = enterpriseEmployeeForm.getEnterpriseId();
+        EnterpriseEntity enterpriseEntity = enterpriseDao.selectById(enterpriseId);
+        if (enterpriseEntity == null || enterpriseEntity.getDeletedFlag()) {
+            return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST);
+        }
+        List<Long> waitDeleteEmployeeIdList = enterpriseEmployeeForm.getEmployeeIdList();
+        enterpriseEmployeeDao.deleteByEnterpriseAndEmployeeIdList(enterpriseId, waitDeleteEmployeeIdList);
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 企业下员工列表
+     *
+     */
+    public List<EnterpriseEmployeeVO> employeeList(List<Long> enterpriseIdList) {
+        if (CollectionUtils.isEmpty(enterpriseIdList)) {
+            return Lists.newArrayList();
+        }
+        return enterpriseEmployeeDao.selectByEnterpriseIdList(enterpriseIdList);
+    }
+
+    /**
+     * 分页查询企业员工
+     *
+     */
+    public PageResult<EnterpriseEmployeeVO> queryPageEmployeeList(EnterpriseEmployeeQueryForm queryForm) {
+        Page<?> page = BlinkPageUtil.convert2PageQuery(queryForm);
+        List<EnterpriseEmployeeVO> enterpriseEmployeeVOList = enterpriseEmployeeDao.queryPageEmployeeList(page, queryForm);
+        for (EnterpriseEmployeeVO enterpriseEmployeeVO : enterpriseEmployeeVOList) {
+            enterpriseEmployeeVO.setDepartmentName(departmentService.getDepartmentPath(enterpriseEmployeeVO.getDepartmentId()));
+        }
+        return BlinkPageUtil.convert2PageResult(page, enterpriseEmployeeVOList);
+    }
+}

+ 45 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/constant/EnterpriseTypeEnum.java

@@ -0,0 +1,45 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.constant;
+
+
+import com.cloud.sa.base.common.enumeration.BaseEnum;
+
+/**
+ * 企业类型
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ *
+ */
+public enum EnterpriseTypeEnum implements BaseEnum {
+
+    /**
+     * 有限企业
+     */
+    NORMAL(1, "有限企业"),
+
+    /**
+     * 外资企业
+     */
+    FOREIGN(2, "外资企业"),
+    ;
+
+    private Integer value;
+    private String desc;
+
+    EnterpriseTypeEnum(Integer value, String desc) {
+        this.value = value;
+        this.desc = desc;
+    }
+
+
+    @Override
+    public Integer getValue() {
+        return value;
+    }
+
+    @Override
+    public String getDesc() {
+        return desc;
+    }
+}

+ 64 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/dao/EnterpriseDao.java

@@ -0,0 +1,64 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEntity;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.form.EnterpriseQueryForm;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseListVO;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 企业
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ *
+ */
+@Mapper
+@Component
+public interface EnterpriseDao extends BaseMapper<EnterpriseEntity> {
+
+    /**
+     * 根据企业名称查询
+     *
+     */
+    EnterpriseEntity queryByEnterpriseName(@Param("enterpriseName") String enterpriseName, @Param("excludeEnterpriseId") Long excludeEnterpriseId, @Param("deletedFlag") Boolean deletedFlag);
+
+    /**
+     * 删除企业
+     */
+    void deleteEnterprise(@Param("enterpriseId") Long enterpriseId, @Param("deletedFlag") Boolean deletedFlag);
+
+    /**
+     * 企业分页查询
+     *
+     */
+    List<EnterpriseVO> queryPage(Page page, @Param("queryForm") EnterpriseQueryForm queryForm);
+
+    /**
+     * 查询导出的数据
+     *
+     */
+    List<EnterpriseExcelVO> selectExcelExportData(@Param("queryForm") EnterpriseQueryForm queryForm);
+
+    /**
+     * 查询企业详情
+     *
+     */
+    EnterpriseVO getDetail(@Param("enterpriseId") Long enterpriseId, @Param("deletedFlag") Boolean deletedFlag);
+
+    /**
+     * 查询列表
+     *
+     */
+    List<EnterpriseListVO> queryList(@Param("type") Integer type, @Param("disabledFlag") Boolean disabledFlag, @Param("deletedFlag") Boolean deletedFlag);
+
+
+}

+ 69 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/dao/EnterpriseEmployeeDao.java

@@ -0,0 +1,69 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEmployeeEntity;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.form.EnterpriseEmployeeQueryForm;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEmployeeVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 企业员工
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ *
+ */
+@Mapper
+@Component
+public interface EnterpriseEmployeeDao extends BaseMapper<EnterpriseEmployeeEntity> {
+
+
+    /**
+     * 根据员工查询
+     */
+    List<EnterpriseEmployeeVO> selectByEmployeeIdList(@Param("employeeIdList")Collection<Long> employeeIdList);
+
+    /**
+     * 查询员工关联的企业
+     */
+    List<Long> selectEnterpriseIdByEmployeeId(@Param("employeeId")Long employeeId);
+    /**
+     * 根据企业查询
+     */
+    List<EnterpriseEmployeeVO> selectByEnterpriseIdList(@Param("enterpriseIdList")Collection<Long> enterpriseIdList);
+    /**
+     * 根据企业查询
+     */
+    List<EnterpriseEmployeeEntity> selectByEnterpriseId(@Param("enterpriseId")Long enterpriseId);
+
+    /**
+     * 查询企业下的所有员工id
+     */
+    List<Long> selectEmployeeIdByEnterpriseIdList(@Param("enterpriseIdList")Collection<Long> enterpriseIdList);
+    /**
+     * 根据员工删除
+     */
+    void deleteByEnterpriseAndEmployeeIdList(@Param("enterpriseId")Long enterpriseId, @Param("employeeIdList")Collection<Long> employeeIdList);
+
+    /**
+     * 根据员工查询
+     */
+    List<EnterpriseEmployeeEntity> selectByEnterpriseAndEmployeeIdList(@Param("enterpriseId")Long enterpriseId, @Param("employeeIdList")Collection<Long> employeeIdList);
+
+    /**
+     * 删除某员工关联的所有企业
+     */
+    void deleteByEmployeeId(@Param("employeeId")Long employeeId);
+
+    /**
+     * 分页查询企业员工
+     */
+    List<EnterpriseEmployeeVO> queryPageEmployeeList(Page<?> page,@Param("queryForm") EnterpriseEmployeeQueryForm queryForm);
+}

+ 50 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/entity/EnterpriseEmployeeEntity.java

@@ -0,0 +1,50 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 企业员工
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ *
+ */
+@Data
+@TableName("t_oa_enterprise_employee")
+@NoArgsConstructor
+public class EnterpriseEmployeeEntity {
+
+    @TableId(type = IdType.AUTO)
+    private Long enterpriseEmployeeId;
+
+    /**
+     * 企业ID
+     */
+    private Long enterpriseId;
+    /**
+     * 员工
+     */
+    private Long employeeId;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    public EnterpriseEmployeeEntity(Long enterpriseId, Long employeeId) {
+        this.enterpriseId = enterpriseId;
+        this.employeeId = employeeId;
+    }
+}

+ 152 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/entity/EnterpriseEntity.java

@@ -0,0 +1,152 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import com.cloud.sa.admin.module.business.oa.enterprise.constant.EnterpriseTypeEnum;
+import com.cloud.sa.base.module.support.datatracer.annoation.DataTracerFieldEnum;
+import com.cloud.sa.base.module.support.datatracer.annoation.DataTracerFieldLabel;
+
+import java.time.LocalDateTime;
+
+/**
+ * 企业
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ *
+ */
+@Data
+@TableName("t_oa_enterprise")
+public class EnterpriseEntity {
+
+    /**
+     * 企业ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long enterpriseId;
+
+    /**
+     * 企业名称
+     */
+    @DataTracerFieldLabel("企业名称")
+    private String enterpriseName;
+
+    /**
+     * 企业logo
+     */
+    @DataTracerFieldLabel("企业logo")
+    private String enterpriseLogo;
+
+    /**
+     * 统一社会信用代码
+     */
+    @DataTracerFieldLabel("统一社会信用代码")
+    private String unifiedSocialCreditCode;
+
+    /**
+     * 类型
+     *
+     * @see EnterpriseTypeEnum
+     */
+    @DataTracerFieldLabel("类型")
+    @DataTracerFieldEnum(enumClass = EnterpriseTypeEnum.class)
+    private Integer type;
+
+    /**
+     * 联系人
+     */
+    @DataTracerFieldLabel("联系人")
+    private String contact;
+
+    /**
+     * 联系人电话
+     */
+    @DataTracerFieldLabel("联系人电话")
+    private String contactPhone;
+
+    /**
+     * 邮箱
+     */
+    @DataTracerFieldLabel("邮箱")
+    private String email;
+
+    /**
+     * 省份
+     */
+    private Integer province;
+
+    /**
+     * 省份名称
+     */
+    @DataTracerFieldLabel("省份名称")
+    private String provinceName;
+
+    /**
+     * 城市
+     */
+    private Integer city;
+
+    /**
+     * 城市名称
+     */
+    @DataTracerFieldLabel("城市名称")
+    private String cityName;
+
+    /**
+     * 区县
+     */
+    private Integer district;
+
+    /**
+     * 区县名称
+     */
+    @DataTracerFieldLabel("区县名称")
+    private String districtName;
+
+    /**
+     * 详细地址
+     */
+    @DataTracerFieldLabel("详细地址")
+    private String address;
+
+    /**
+     * 营业执照
+     */
+    @DataTracerFieldLabel("营业执照")
+    private String businessLicense;
+
+    /**
+     * 禁用状态
+     */
+    @DataTracerFieldLabel("禁用状态")
+    private Boolean disabledFlag;
+
+    /**
+     * 删除状态
+     */
+    @DataTracerFieldLabel("删除状态")
+    private Boolean deletedFlag;
+
+    /**
+     * 创建人ID
+     */
+    private Long createUserId;
+
+    /**
+     * 创建人ID
+     */
+    private String createUserName;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 100 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseCreateForm.java

@@ -0,0 +1,100 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.form;
+
+import com.cloud.sa.admin.module.business.oa.enterprise.constant.EnterpriseTypeEnum;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.json.deserializer.FileKeyVoDeserializer;
+import com.cloud.sa.base.common.json.serializer.FileKeyVoSerializer;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+import com.cloud.sa.base.common.util.BlinkVerificationUtil;
+import com.cloud.sa.base.common.validator.enumeration.CheckEnum;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+/**
+ * OA企业模块创建
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ *
+ */
+@Data
+public class EnterpriseCreateForm {
+
+    @Schema(description = "企业名称")
+    @NotBlank(message = "企业名称不能为空")
+    @Length(max = 200, message = "企业名称最多200字符")
+    private String enterpriseName;
+
+    @Schema(description = "企业logo")
+    @JsonSerialize(using = FileKeyVoSerializer.class)
+    @JsonDeserialize(using = FileKeyVoDeserializer.class)
+    private String enterpriseLogo;
+
+    @Schema(description = "统一社会信用代码")
+    @NotBlank(message = "统一社会信用代码不能为空")
+    @Length(max = 200, message = "统一社会信用代码最多200字符")
+    private String unifiedSocialCreditCode;
+
+    @Schema(description = "联系人")
+    @NotBlank(message = "联系人不能为空")
+    @Length(max = 100, message = "联系人最多100字符")
+    private String contact;
+
+    @Schema(description = "联系人电话")
+    @NotBlank(message = "联系人电话不能为空")
+    @Pattern(regexp = BlinkVerificationUtil.PHONE_REGEXP, message = "手机号格式不正确")
+    private String contactPhone;
+
+    @SchemaEnum(desc = "类型", value = EnterpriseTypeEnum.class)
+    @CheckEnum(message = "类型不正确", value = EnterpriseTypeEnum.class)
+    private Integer type;
+
+    @Schema(description = "邮箱")
+    @Pattern(regexp = BlinkVerificationUtil.EMAIL, message = "邮箱格式不正确")
+    private String email;
+
+    @Schema(description = "省份")
+    private Integer province;
+
+    @Schema(description = "省份名称")
+    private String provinceName;
+
+    @Schema(description = "城市")
+    private Integer city;
+
+    @Schema(description = "城市名称")
+    private String cityName;
+
+    @Schema(description = "区县")
+    private Integer district;
+
+    @Schema(description = "区县名称")
+    private String districtName;
+
+    @Schema(description = "详细地址")
+    @Length(max = 500, message = "详细地址最多500字符")
+    private String address;
+
+    @Schema(description = "营业执照")
+    @JsonSerialize(using = FileKeyVoSerializer.class)
+    @JsonDeserialize(using = FileKeyVoDeserializer.class)
+    private String businessLicense;
+
+    @Schema(description = "禁用状态")
+    @NotNull(message = "禁用状态不能为空")
+    private Boolean disabledFlag;
+
+    @Schema(description = "创建人", hidden = true)
+    private Long createUserId;
+
+    @Schema(description = "创建人", hidden = true)
+    private String createUserName;
+
+}

+ 28 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseEmployeeForm.java

@@ -0,0 +1,28 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 企业员工
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ * 
+ */
+@Data
+public class EnterpriseEmployeeForm {
+
+    @Schema(description = "企业id")
+    @NotNull(message = "企业id不能为空")
+    private Long enterpriseId;
+
+    @Schema(description = "员工信息id")
+    @NotEmpty(message = "员工信息id不能为空")
+    private List<Long> employeeIdList;
+}

+ 32 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseEmployeeQueryForm.java

@@ -0,0 +1,32 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.domain.PageParam;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 查询企业员工
+ *
+ * @Author 云畅联: admin
+ * @Date 2021-12-20 21:06:49
+
+ *
+ */
+@Data
+public class EnterpriseEmployeeQueryForm extends PageParam {
+
+    @Schema(description = "搜索词")
+    @Length(max = 20, message = "搜索词最多20字符")
+    private String keyword;
+
+    @Schema(description = "公司Id")
+    @NotNull(message = "公司id 不能为空")
+    private Long enterpriseId;
+
+    @Schema(description = "删除标识", hidden = true)
+    private Boolean deletedFlag;
+
+}

+ 37 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseQueryForm.java

@@ -0,0 +1,37 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.domain.PageParam;
+import org.hibernate.validator.constraints.Length;
+
+import java.time.LocalDate;
+
+/**
+ * OA企业模块分页查询
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ * 
+ */
+@Data
+public class EnterpriseQueryForm extends PageParam {
+
+    @Schema(description = "关键字")
+    @Length(max = 200, message = "关键字最多200字符")
+    private String keywords;
+
+    @Schema(description = "开始时间")
+    private LocalDate startTime;
+
+    @Schema(description = "结束时间")
+    private LocalDate endTime;
+
+    @Schema(description = "禁用状态")
+    private Boolean disabledFlag;
+
+    @Schema(description = "删除状态", hidden = true)
+    private Boolean deletedFlag;
+
+}

+ 22 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseUpdateForm.java

@@ -0,0 +1,22 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * OA企业模块编辑
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ *
+ */
+@Data
+public class EnterpriseUpdateForm extends EnterpriseCreateForm {
+
+    @Schema(description = "企业ID")
+    @NotNull(message = "企业ID不能为空")
+    private Long enterpriseId;
+}

+ 46 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseEmployeeVO.java

@@ -0,0 +1,46 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 企业员工信息
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ *
+ */
+@Data
+public class EnterpriseEmployeeVO {
+
+    private Long enterpriseEmployeeId;
+
+    @Schema(description = "企业ID")
+    private Long enterpriseId;
+
+    @Schema(description = "企业名称")
+    private String enterpriseName;
+
+    @Schema(description = "员工")
+    private Long employeeId;
+
+    @Schema(description = "登录账号")
+    private String loginName;
+
+    @Schema(description = "员工名称")
+    private String actualName;
+
+    @Schema(description = "手机号码")
+    private String phone;
+
+    @Schema(description = "部门id")
+    private Long departmentId;
+
+    @Schema(description = "是否被禁用")
+    private Boolean disabledFlag;
+
+    @Schema(description = "部门名称")
+    private String departmentName;
+
+}

+ 47 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseExcelVO.java

@@ -0,0 +1,47 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+/**
+ * 企业信息
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ * 
+ */
+@Data
+public class EnterpriseExcelVO {
+
+    @ExcelProperty("企业名称")
+    private String enterpriseName;
+
+    @ExcelProperty("统一社会信用代码")
+    private String unifiedSocialCreditCode;
+
+    @ExcelProperty("企业类型")
+    private String typeName;
+
+    @ExcelProperty("联系人")
+    private String contact;
+
+    @ExcelProperty("联系人电话")
+    private String contactPhone;
+
+    @ExcelProperty("邮箱")
+    private String email;
+
+    @ExcelProperty("省份名称")
+    private String provinceName;
+
+    @ExcelProperty("城市名称")
+    private String cityName;
+
+    @ExcelProperty("区县名称")
+    private String districtName;
+
+    @ExcelProperty("详细地址")
+    private String address;
+
+}

+ 20 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseListVO.java

@@ -0,0 +1,20 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * OA企业模块列表
+ *
+ * @author admin
+ * @date 2022/6/23 14:31
+ */
+@Data
+public class EnterpriseListVO {
+
+    @Schema(description = "企业ID")
+    private Long enterpriseId;
+
+    @Schema(description = "企业名称")
+    private String enterpriseName;
+}

+ 88 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseVO.java

@@ -0,0 +1,88 @@
+package com.cloud.sa.admin.module.business.oa.enterprise.domain.vo;
+
+import com.cloud.sa.admin.module.business.oa.enterprise.constant.EnterpriseTypeEnum;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.json.serializer.FileKeyVoSerializer;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+
+import java.time.LocalDateTime;
+
+/**
+ * 企业信息
+ *
+ * @Author 云畅联: admin
+ * @Date 2022/7/28 20:37:15
+
+ *
+ */
+@Data
+public class EnterpriseVO {
+
+    @Schema(description = "企业ID")
+    private Long enterpriseId;
+
+    @Schema(description = "企业名称")
+    private String enterpriseName;
+
+    @Schema(description = "企业logo")
+    @JsonSerialize(using = FileKeyVoSerializer.class)
+    private String enterpriseLogo;
+
+    @Schema(description = "统一社会信用代码")
+    private String unifiedSocialCreditCode;
+
+    @SchemaEnum(desc = "类型", value = EnterpriseTypeEnum.class)
+    private Integer type;
+
+    @Schema(description = "联系人")
+    private String contact;
+
+    @Schema(description = "联系人电话")
+    private String contactPhone;
+
+    @Schema(description = "邮箱")
+    private String email;
+
+    @Schema(description = "省份")
+    private Integer province;
+
+    @Schema(description = "省份名称")
+    private String provinceName;
+
+    @Schema(description = "城市")
+    private Integer city;
+
+    @Schema(description = "城市名称")
+    private String cityName;
+
+    @Schema(description = "区县")
+    private Integer district;
+
+    @Schema(description = "区县名称")
+    private String districtName;
+
+    @Schema(description = "详细地址")
+    private String address;
+
+    @Schema(description = "营业执照")
+    @JsonSerialize(using = FileKeyVoSerializer.class)
+    private String businessLicense;
+
+    @Schema(description = "禁用状态")
+    private Boolean disabledFlag;
+
+    @Schema(description = "创建人ID")
+    private Long createUserId;
+
+    @Schema(description = "创建人名称")
+    private String createUserName;
+
+    @Schema(description = "创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "更新时间")
+    private LocalDateTime updateTime;
+
+}

+ 79 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/InvoiceController.java

@@ -0,0 +1,79 @@
+package com.cloud.sa.admin.module.business.oa.invoice;
+
+import com.cloud.sa.admin.constant.AdminSwaggerTagConst;
+import com.cloud.sa.admin.module.business.oa.invoice.domain.InvoiceAddForm;
+import com.cloud.sa.admin.module.business.oa.invoice.domain.InvoiceQueryForm;
+import com.cloud.sa.admin.module.business.oa.invoice.domain.InvoiceUpdateForm;
+import com.cloud.sa.admin.module.business.oa.invoice.domain.InvoiceVO;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.extern.slf4j.Slf4j;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.RequestUser;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.util.BlinkRequestUtil;
+import com.cloud.sa.base.module.support.operatelog.annotation.OperateLog;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * OA发票信息
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-06-23 19:32:59
+
+ *
+ */
+@Slf4j
+@RestController
+@Tag(name = AdminSwaggerTagConst.Business.OA_INVOICE)
+public class InvoiceController {
+
+    @Resource
+    private InvoiceService invoiceService;
+
+    @Operation(summary = "分页查询发票信息 @author admin")
+    @PostMapping("/oa/invoice/page/query")
+    public ResponseDTO<PageResult<InvoiceVO>> queryByPage(@RequestBody @Valid InvoiceQueryForm queryForm) {
+        return invoiceService.queryByPage(queryForm);
+    }
+
+    @Operation(summary = "查询发票信息详情 @author admin")
+    @GetMapping("/oa/invoice/get/{invoiceId}")
+    public ResponseDTO<InvoiceVO> getDetail(@PathVariable Long invoiceId) {
+        return invoiceService.getDetail(invoiceId);
+    }
+
+    @Operation(summary = "新建发票信息 @author admin")
+    @PostMapping("/oa/invoice/create")
+    public ResponseDTO<String> createInvoice(@RequestBody @Valid InvoiceAddForm createVO) {
+        RequestUser requestUser = BlinkRequestUtil.getRequestUser();
+        createVO.setCreateUserId(requestUser.getUserId());
+        createVO.setCreateUserName(requestUser.getUserName());
+        return invoiceService.createInvoice(createVO);
+    }
+
+    @Operation(summary = "编辑发票信息 @author admin")
+    @PostMapping("/oa/invoice/update")
+    @OperateLog
+    public ResponseDTO<String> updateInvoice(@RequestBody @Valid InvoiceUpdateForm updateVO) {
+        return invoiceService.updateInvoice(updateVO);
+    }
+
+    @Operation(summary = "删除发票信息 @author admin")
+    @GetMapping("/invoice/delete/{invoiceId}")
+    public ResponseDTO<String> deleteInvoice(@PathVariable Long invoiceId) {
+        return invoiceService.deleteInvoice(invoiceId);
+    }
+
+    @Operation(summary = "查询列表 @author lidoudou")
+    @GetMapping("/oa/invoice/query/list/{enterpriseId}")
+    public ResponseDTO<List<InvoiceVO>> queryList(@PathVariable Long enterpriseId) {
+        return invoiceService.queryList(enterpriseId);
+    }
+
+
+}

+ 60 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/InvoiceDao.java

@@ -0,0 +1,60 @@
+package com.cloud.sa.admin.module.business.oa.invoice;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.oa.invoice.domain.InvoiceVO;
+import com.cloud.sa.admin.module.business.oa.invoice.domain.InvoiceEntity;
+import com.cloud.sa.admin.module.business.oa.invoice.domain.InvoiceQueryForm;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * OA发票信息
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-06-23 19:32:59
+
+ *
+ */
+@Mapper
+@Component
+public interface InvoiceDao extends BaseMapper<InvoiceEntity> {
+
+    /**
+     * 根据账号查询
+     * @param enterpriseId
+     * @param accountNumber
+     * @param excludeInvoiceId
+     * @param deletedFlag
+     * @return
+     */
+    InvoiceEntity queryByAccountNumber(@Param("enterpriseId") Long enterpriseId, @Param("accountNumber") String accountNumber, @Param("excludeInvoiceId") Long excludeInvoiceId, @Param("deletedFlag") Boolean deletedFlag);
+
+    /**
+     * 删除发票信息
+     *
+     * @param invoiceId
+     * @param deletedFlag
+     */
+    void deleteInvoice(@Param("invoiceId") Long invoiceId, @Param("deletedFlag") Boolean deletedFlag);
+
+    /**
+     * 发票信息分页查询
+     *
+     * @param page
+     * @param queryForm
+     * @return
+     */
+    List<InvoiceVO> queryPage(Page page, @Param("queryForm") InvoiceQueryForm queryForm);
+
+    /**
+     * 查询发票信息详情
+     * @param invoiceId
+     * @param deletedFlag
+     * @return
+     */
+    InvoiceVO getDetail(@Param("invoiceId") Long invoiceId, @Param("deletedFlag") Boolean deletedFlag);
+}

+ 142 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/InvoiceService.java

@@ -0,0 +1,142 @@
+package com.cloud.sa.admin.module.business.oa.invoice;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.oa.enterprise.EnterpriseService;
+import com.cloud.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO;
+import com.cloud.sa.admin.module.business.oa.invoice.domain.*;
+import lombok.extern.slf4j.Slf4j;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.util.BlinkBeanUtil;
+import com.cloud.sa.base.common.util.BlinkPageUtil;
+import com.cloud.sa.base.module.support.datatracer.constant.DataTracerConst;
+import com.cloud.sa.base.module.support.datatracer.constant.DataTracerTypeEnum;
+import com.cloud.sa.base.module.support.datatracer.service.DataTracerService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * OA发票信息
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-06-23 19:32:59
+
+ * 
+ */
+@Service
+@Slf4j
+public class InvoiceService {
+
+    @Resource
+    private InvoiceDao invoiceDao;
+
+    @Resource
+    private EnterpriseService enterpriseService;
+
+    @Resource
+    private DataTracerService dataTracerService;
+
+    /**
+     * 分页查询发票信息
+     */
+    public ResponseDTO<PageResult<InvoiceVO>> queryByPage(InvoiceQueryForm queryForm) {
+        queryForm.setDeletedFlag(Boolean.FALSE);
+        Page<?> page = BlinkPageUtil.convert2PageQuery(queryForm);
+        List<InvoiceVO> invoiceList = invoiceDao.queryPage(page, queryForm);
+        PageResult<InvoiceVO> pageResult = BlinkPageUtil.convert2PageResult(page, invoiceList);
+        return ResponseDTO.ok(pageResult);
+    }
+
+    public ResponseDTO<List<InvoiceVO>> queryList(Long enterpriseId) {
+        InvoiceQueryForm queryForm = new InvoiceQueryForm();
+        queryForm.setDeletedFlag(Boolean.FALSE);
+        queryForm.setDisabledFlag(Boolean.FALSE);
+        queryForm.setEnterpriseId(enterpriseId);
+        List<InvoiceVO> invoiceList = invoiceDao.queryPage(null, queryForm);
+        return ResponseDTO.ok(invoiceList);
+    }
+
+    /**
+     * 查询发票信息详情
+     */
+    public ResponseDTO<InvoiceVO> getDetail(Long invoiceId) {
+        // 校验发票信息是否存在
+        InvoiceVO invoiceVO = invoiceDao.getDetail(invoiceId, Boolean.FALSE);
+        if (Objects.isNull(invoiceVO)) {
+            return ResponseDTO.userErrorParam("发票信息不存在");
+        }
+        return ResponseDTO.ok(invoiceVO);
+    }
+
+    /**
+     * 新建发票信息
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> createInvoice(InvoiceAddForm createVO) {
+        Long enterpriseId = createVO.getEnterpriseId();
+        // 校验企业是否存在
+        EnterpriseVO enterpriseVO = enterpriseService.getDetail(enterpriseId);
+        if (Objects.isNull(enterpriseVO)) {
+            return ResponseDTO.userErrorParam("企业不存在");
+        }
+        // 验证发票信息账号是否重复
+        InvoiceEntity validateInvoice = invoiceDao.queryByAccountNumber(enterpriseId, createVO.getAccountNumber(), null, Boolean.FALSE);
+        if (Objects.nonNull(validateInvoice)) {
+            return ResponseDTO.userErrorParam("发票信息账号重复");
+        }
+        // 数据插入
+        InvoiceEntity insertInvoice = BlinkBeanUtil.copy(createVO, InvoiceEntity.class);
+        invoiceDao.insert(insertInvoice);
+        dataTracerService.addTrace(enterpriseId, DataTracerTypeEnum.OA_ENTERPRISE, "新增发票:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(insertInvoice));
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 编辑发票信息
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> updateInvoice(InvoiceUpdateForm updateVO) {
+        Long enterpriseId = updateVO.getEnterpriseId();
+        // 校验企业是否存在
+        EnterpriseVO enterpriseVO = enterpriseService.getDetail(enterpriseId);
+        if (Objects.isNull(enterpriseVO)) {
+            return ResponseDTO.userErrorParam("企业不存在");
+        }
+        Long invoiceId = updateVO.getInvoiceId();
+        // 校验发票信息是否存在
+        InvoiceEntity invoiceDetail = invoiceDao.selectById(invoiceId);
+        if (Objects.isNull(invoiceDetail) || invoiceDetail.getDeletedFlag()) {
+            return ResponseDTO.userErrorParam("发票信息不存在");
+        }
+        // 验证发票信息账号是否重复
+        InvoiceEntity validateInvoice = invoiceDao.queryByAccountNumber(updateVO.getEnterpriseId(), updateVO.getAccountNumber(), invoiceId, Boolean.FALSE);
+        if (Objects.nonNull(validateInvoice)) {
+            return ResponseDTO.userErrorParam("发票信息账号重复");
+        }
+        // 数据编辑
+        InvoiceEntity updateInvoice = BlinkBeanUtil.copy(updateVO, InvoiceEntity.class);
+        invoiceDao.updateById(updateInvoice);
+        dataTracerService.addTrace(enterpriseId, DataTracerTypeEnum.OA_ENTERPRISE, "更新发票:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(invoiceDetail, updateInvoice));
+        return ResponseDTO.ok();
+    }
+
+
+    /**
+     * 删除发票信息
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseDTO<String> deleteInvoice(Long invoiceId) {
+        // 校验发票信息是否存在
+        InvoiceEntity invoiceDetail = invoiceDao.selectById(invoiceId);
+        if (Objects.isNull(invoiceDetail) || invoiceDetail.getDeletedFlag()) {
+            return ResponseDTO.userErrorParam("发票信息不存在");
+        }
+        invoiceDao.deleteInvoice(invoiceId, Boolean.TRUE);
+        dataTracerService.addTrace(invoiceDetail.getEnterpriseId(), DataTracerTypeEnum.OA_ENTERPRISE, "删除发票:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(invoiceDetail));
+        return ResponseDTO.ok();
+    }
+}

+ 58 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/domain/InvoiceAddForm.java

@@ -0,0 +1,58 @@
+package com.cloud.sa.admin.module.business.oa.invoice.domain;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * OA发票信息新建
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-06-23 19:32:59
+
+ *
+ */
+@Data
+public class InvoiceAddForm {
+
+    @Schema(description = "开票抬头")
+    @NotBlank(message = "开票抬头不能为空")
+    @Length(max = 200, message = "开票抬头最多200字符")
+    private String invoiceHeads;
+
+    @Schema(description = "纳税人识别号")
+    @NotBlank(message = "纳税人识别号不能为空")
+    @Length(max = 200, message = "纳税人识别号最多200字符")
+    private String taxpayerIdentificationNumber;
+
+    @Schema(description = "银行账户")
+    @NotBlank(message = "银行账户不能为空")
+    @Length(max = 200, message = "银行账户最多200字符")
+    private String accountNumber;
+
+    @Schema(description = "开户行")
+    @NotBlank(message = "开户行不能为空")
+    @Length(max = 200, message = "开户行最多200字符")
+    private String bankName;
+
+    @Schema(description = "启用状态")
+    @NotNull(message = "启用状态不能为空")
+    private Boolean disabledFlag;
+
+    @Schema(description = "备注")
+    @Length(max = 500, message = "备注最多500字符")
+    private String remark;
+
+    @Schema(description = "企业")
+    @NotNull(message = "企业不能为空")
+    private Long enterpriseId;
+
+    @Schema(description = "创建人", hidden = true)
+    private Long createUserId;
+
+    @Schema(description = "创建人名称", hidden = true)
+    private String createUserName;
+}

+ 97 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/domain/InvoiceEntity.java

@@ -0,0 +1,97 @@
+package com.cloud.sa.admin.module.business.oa.invoice.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import com.cloud.sa.base.module.support.datatracer.annoation.DataTracerFieldLabel;
+
+import java.time.LocalDateTime;
+
+/**
+ * OA发票信息
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-06-23 19:32:59
+
+ *
+ */
+@Data
+@TableName("t_oa_invoice")
+public class InvoiceEntity {
+
+    /**
+     * 发票信息ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long invoiceId;
+
+    /**
+     * 开票抬头
+     */
+    @DataTracerFieldLabel("开票抬头")
+    private String invoiceHeads;
+
+    /**
+     * 纳税人识别号
+     */
+    @DataTracerFieldLabel("纳税人识别号")
+    private String taxpayerIdentificationNumber;
+
+    /**
+     * 银行账户
+     */
+    @DataTracerFieldLabel("银行账户")
+    private String accountNumber;
+
+    /**
+     * 开户行
+     */
+    @DataTracerFieldLabel("开户行")
+    private String bankName;
+
+    /**
+     * 备注
+     */
+    @DataTracerFieldLabel("备注")
+    private String remark;
+
+    /**
+     * 企业ID
+     */
+    private Long enterpriseId;
+
+    /**
+     * 禁用状态
+     */
+    @DataTracerFieldLabel("禁用状态")
+    private Boolean disabledFlag;
+
+    /**
+     * 删除状态
+     */
+    @DataTracerFieldLabel("删除状态")
+    private Boolean deletedFlag;
+
+    /**
+     * 创建人ID
+     */
+    private Long createUserId;
+
+    /**
+     * 创建人ID
+     */
+    private String createUserName;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+
+}

+ 39 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/domain/InvoiceQueryForm.java

@@ -0,0 +1,39 @@
+package com.cloud.sa.admin.module.business.oa.invoice.domain;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.domain.PageParam;
+import org.hibernate.validator.constraints.Length;
+
+import java.time.LocalDate;
+
+/**
+ * OA发票信息查询
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-06-23 19:32:59
+
+ * 
+ */
+@Data
+public class InvoiceQueryForm extends PageParam {
+
+    @Schema(description = "企业ID")
+    private Long enterpriseId;
+
+    @Schema(description = "关键字")
+    @Length(max = 200, message = "关键字最多200字符")
+    private String keywords;
+
+    @Schema(description = "开始时间")
+    private LocalDate startTime;
+
+    @Schema(description = "结束时间")
+    private LocalDate endTime;
+
+    @Schema(description = "禁用状态")
+    private Boolean disabledFlag;
+
+    @Schema(description = "删除状态", hidden = true)
+    private Boolean deletedFlag;
+}

+ 22 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/domain/InvoiceUpdateForm.java

@@ -0,0 +1,22 @@
+package com.cloud.sa.admin.module.business.oa.invoice.domain;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * OA发票信息编辑
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-06-23 19:32:59
+
+ * 
+ */
+@Data
+public class InvoiceUpdateForm extends InvoiceAddForm {
+
+    @Schema(description = "发票信息ID")
+    @NotNull(message = "发票信息ID不能为空")
+    private Long invoiceId;
+}

+ 57 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/invoice/domain/InvoiceVO.java

@@ -0,0 +1,57 @@
+package com.cloud.sa.admin.module.business.oa.invoice.domain;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * OA发票信息
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-06-23 19:32:59
+
+ *
+ */
+@Data
+public class InvoiceVO {
+
+    @Schema(description = "发票信息ID")
+    private Long invoiceId;
+
+    @Schema(description = "开票抬头")
+    private String invoiceHeads;
+
+    @Schema(description = "纳税人识别号")
+    private String taxpayerIdentificationNumber;
+
+    @Schema(description = "银行账户")
+    private String accountNumber;
+
+    @Schema(description = "开户行")
+    private String bankName;
+
+    @Schema(description = "备注")
+    private String remark;
+
+    @Schema(description = "企业")
+    private Long enterpriseId;
+
+    @Schema(description = "企业名称")
+    private String enterpriseName;
+
+    @Schema(description = "禁用状态")
+    private Boolean disabledFlag;
+
+    @Schema(description = "创建人ID")
+    private Long createUserId;
+
+    @Schema(description = "创建人名称")
+    private String createUserName;
+
+    @Schema(description = "创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "更新时间")
+    private LocalDateTime updateTime;
+}

+ 35 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/constant/NoticeVisibleRangeDataTypeEnum.java

@@ -0,0 +1,35 @@
+package com.cloud.sa.admin.module.business.oa.notice.constant;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import com.cloud.sa.base.common.enumeration.BaseEnum;
+
+/**
+ * 公告、通知 可见范围类型
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Getter
+@AllArgsConstructor
+public enum NoticeVisibleRangeDataTypeEnum implements BaseEnum {
+
+    /**
+     * 员工
+     */
+    EMPLOYEE(1, "员工"),
+
+    /**
+     * 部门
+     */
+    DEPARTMENT(2, "部门"),
+
+    ;
+
+    private final Integer value;
+
+    private final String desc;
+}

+ 139 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/controller/NoticeController.java

@@ -0,0 +1,139 @@
+package com.cloud.sa.admin.module.business.oa.notice.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.extra.servlet.ServletUtil;
+import com.cloud.sa.admin.constant.AdminSwaggerTagConst;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.*;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.*;
+import com.cloud.sa.admin.module.business.oa.notice.service.NoticeEmployeeService;
+import com.cloud.sa.admin.module.business.oa.notice.service.NoticeService;
+import com.cloud.sa.admin.module.business.oa.notice.service.NoticeTypeService;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.util.BlinkRequestUtil;
+import com.cloud.sa.base.module.support.operatelog.annotation.OperateLog;
+import com.cloud.sa.base.module.support.repeatsubmit.annoation.RepeatSubmit;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 公告、通知、新闻等等
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ * 
+ */
+@Tag(name = AdminSwaggerTagConst.Business.OA_NOTICE)
+@RestController
+@OperateLog
+public class NoticeController {
+
+    @Resource
+    private NoticeService noticeService;
+
+    @Resource
+    private NoticeTypeService noticeTypeService;
+
+    @Resource
+    private NoticeEmployeeService noticeEmployeeService;
+
+    // --------------------- 通知公告类型 -------------------------
+
+    @Operation(summary = "通知公告类型-获取全部 @author admin")
+    @GetMapping("/oa/noticeType/getAll")
+    public ResponseDTO<List<NoticeTypeVO>> getAll() {
+        return ResponseDTO.ok(noticeTypeService.getAll());
+    }
+
+    @Operation(summary = "通知公告类型-添加 @author admin")
+    @GetMapping("/oa/noticeType/add/{name}")
+    public ResponseDTO<String> add(@PathVariable String name) {
+        return noticeTypeService.add(name);
+    }
+
+    @Operation(summary = "通知公告类型-修改 @author admin")
+    @GetMapping("/oa/noticeType/update/{noticeTypeId}/{name}")
+    public ResponseDTO<String> update(@PathVariable Long noticeTypeId, @PathVariable String name) {
+        return noticeTypeService.update(noticeTypeId, name);
+    }
+
+    @Operation(summary = "通知公告类型-删除 @author admin")
+    @GetMapping("/oa/noticeType/delete/{noticeTypeId}")
+    public ResponseDTO<String> deleteNoticeType(@PathVariable Long noticeTypeId) {
+        return noticeTypeService.delete(noticeTypeId);
+    }
+
+    // --------------------- 【管理】通知公告-------------------------
+
+
+    @Operation(summary = "【管理】通知公告-分页查询 @author admin")
+    @PostMapping("/oa/notice/query")
+    @SaCheckPermission("oa:notice:query")
+    public ResponseDTO<PageResult<NoticeVO>> query(@RequestBody @Valid NoticeQueryForm queryForm) {
+        return ResponseDTO.ok(noticeService.query(queryForm));
+    }
+
+    @Operation(summary = "【管理】通知公告-添加 @author admin")
+    @PostMapping("/oa/notice/add")
+    @RepeatSubmit
+    @SaCheckPermission("oa:notice:add")
+    public ResponseDTO<String> add(@RequestBody @Valid NoticeAddForm addForm) {
+        addForm.setCreateUserId(BlinkRequestUtil.getRequestUserId());
+        return noticeService.add(addForm);
+    }
+
+    @Operation(summary = "【管理】通知公告-更新 @author admin")
+    @PostMapping("/oa/notice/update")
+    @RepeatSubmit
+    @SaCheckPermission("oa:notice:update")
+    public ResponseDTO<String> update(@RequestBody @Valid NoticeUpdateForm updateForm) {
+        return noticeService.update(updateForm);
+    }
+
+    @Operation(summary = "【管理】通知公告-更新详情 @author admin")
+    @GetMapping("/oa/notice/getUpdateVO/{noticeId}")
+    @SaCheckPermission("oa:notice:update")
+    public ResponseDTO<NoticeUpdateFormVO> getUpdateFormVO(@PathVariable Long noticeId) {
+        return ResponseDTO.ok(noticeService.getUpdateFormVO(noticeId));
+    }
+
+    @Operation(summary = "【管理】通知公告-删除 @author admin")
+    @GetMapping("/oa/notice/delete/{noticeId}")
+    @SaCheckPermission("oa:notice:delete")
+    public ResponseDTO<String> delete(@PathVariable Long noticeId) {
+        return noticeService.delete(noticeId);
+    }
+
+    // --------------------- 【员工】查看 通知公告 -------------------------
+
+
+    @Operation(summary = "【员工】通知公告-查看详情 @author admin")
+    @GetMapping("/oa/notice/employee/view/{noticeId}")
+    public ResponseDTO<NoticeDetailVO> view(@PathVariable Long noticeId, HttpServletRequest request) {
+        return noticeEmployeeService.view(
+                BlinkRequestUtil.getRequestUserId(),
+                noticeId,
+                ServletUtil.getClientIP(request),
+                request.getHeader("User-Agent")
+        );
+    }
+
+    @Operation(summary = "【员工】通知公告-查询全部 @author admin")
+    @PostMapping("/oa/notice/employee/query")
+    public ResponseDTO<PageResult<NoticeEmployeeVO>> queryEmployeeNotice(@RequestBody @Valid NoticeEmployeeQueryForm noticeEmployeeQueryForm) {
+        return noticeEmployeeService.queryList(BlinkRequestUtil.getRequestUserId(), noticeEmployeeQueryForm);
+    }
+
+    @Operation(summary = "【员工】通知公告-查询 查看记录 @author admin")
+    @PostMapping("/oa/notice/employee/queryViewRecord")
+    public ResponseDTO<PageResult<NoticeViewRecordVO>> queryViewRecord(@RequestBody @Valid NoticeViewRecordQueryForm noticeViewRecordQueryForm) {
+        return ResponseDTO.ok(noticeEmployeeService.queryViewRecord(noticeViewRecordQueryForm));
+    }
+}

+ 125 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/dao/NoticeDao.java

@@ -0,0 +1,125 @@
+package com.cloud.sa.admin.module.business.oa.notice.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.oa.notice.domain.entity.NoticeEntity;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeEmployeeQueryForm;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeQueryForm;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeViewRecordQueryForm;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeVisibleRangeForm;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.NoticeEmployeeVO;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.NoticeVO;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.NoticeViewRecordVO;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.NoticeVisibleRangeVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 公告、通知、新闻等等
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ * 
+ */
+@Mapper
+@Component
+public interface NoticeDao extends BaseMapper<NoticeEntity> {
+
+    // ================================= 数据范围相关 【子表】 =================================
+
+    /**
+     * 保存可见范围
+     *
+     */
+    void insertVisibleRange(@Param("noticeId") Long noticeId, @Param("visibleRangeFormList") List<NoticeVisibleRangeForm> visibleRangeFormList);
+
+    /**
+     * 删除可见范围
+     *
+     */
+    void deleteVisibleRange(@Param("noticeId") Long noticeId);
+
+    /**
+     * 相关可见范围
+     *
+     */
+    List<NoticeVisibleRangeVO> queryVisibleRange(@Param("noticeId") Long noticeId);
+
+    // ================================= 通知公告【主表】 相关  =================================
+
+    /**
+     * 后管分页查询资讯
+     *
+     */
+    List<NoticeVO> query(Page<?> page, @Param("query") NoticeQueryForm queryForm);
+
+
+    /**
+     * 更新删除状态
+     *
+     */
+    void updateDeletedFlag(@Param("noticeId") Long noticeId);
+
+    // ================================= 通知公告【员工查看】 相关  =================================
+
+    /**
+     * 查询 员工 查看到的通知公告
+     *
+     */
+    List<NoticeEmployeeVO> queryEmployeeNotice(Page<?> page,
+                                               @Param("requestEmployeeId") Long requestEmployeeId,
+                                               @Param("query") NoticeEmployeeQueryForm noticeEmployeeQueryForm,
+                                               @Param("requestEmployeeDepartmentIdList") List<Long> requestEmployeeDepartmentIdList,
+                                               @Param("deletedFlag") boolean deletedFlag,
+                                               @Param("administratorFlag") boolean administratorFlag,
+                                               @Param("departmentDataType") Integer departmentDataType,
+                                               @Param("employeeDataType") Integer employeeDataType
+
+    );
+
+    /**
+     * 查询 员工 未读的通知公告
+     *
+     */
+    List<NoticeEmployeeVO> queryEmployeeNotViewNotice(Page<?> page,
+                                               @Param("requestEmployeeId") Long requestEmployeeId,
+                                               @Param("query") NoticeEmployeeQueryForm noticeEmployeeQueryForm,
+                                               @Param("requestEmployeeDepartmentIdList") List<Long> requestEmployeeDepartmentIdList,
+                                               @Param("deletedFlag") boolean deletedFlag,
+                                               @Param("administratorFlag") boolean administratorFlag,
+                                               @Param("departmentDataType") Integer departmentDataType,
+                                               @Param("employeeDataType") Integer employeeDataType
+
+    );
+
+    long  viewRecordCount(@Param("noticeId")Long noticeId, @Param("employeeId")Long employeeId);
+
+    /**
+     * 查询通知、公告的 查看记录
+     */
+    List<NoticeViewRecordVO> queryNoticeViewRecordList(Page page, @Param("queryForm") NoticeViewRecordQueryForm noticeViewRecordQueryForm);
+
+    /**
+     * 保存查看记录
+     */
+    void insertViewRecord(@Param("noticeId") Long noticeId, @Param("employeeId") Long employeeId, @Param("ip") String ip, @Param("userAgent") String userAgent,@Param("pageViewCount") Integer pageViewCount);
+
+    /**
+     * 更新查看记录
+     */
+    void updateViewRecord(@Param("noticeId")Long noticeId, @Param("employeeId")Long requestEmployeeId,@Param("ip") String ip, @Param("userAgent")String userAgent);
+
+    /**
+     * 更新 浏览量
+     *
+     * @param noticeId 通知 id
+     * @param pageViewCountIncrement 页面浏览量的增量
+     * @param userViewCountIncrement 用户浏览量的增量
+     */
+    void updateViewCount(@Param("noticeId")Long noticeId,@Param("pageViewCountIncrement") Integer pageViewCountIncrement, @Param("userViewCountIncrement")Integer userViewCountIncrement);
+
+}

+ 20 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/dao/NoticeTypeDao.java

@@ -0,0 +1,20 @@
+package com.cloud.sa.admin.module.business.oa.notice.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cloud.sa.admin.module.business.oa.notice.domain.entity.NoticeTypeEntity;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Component;
+
+/**
+ * 通知公告类型
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Mapper
+@Component
+public interface NoticeTypeDao extends BaseMapper<NoticeTypeEntity> {
+
+}

+ 98 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/entity/NoticeEntity.java

@@ -0,0 +1,98 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 通知公告
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+@TableName("t_notice")
+public class NoticeEntity {
+
+    @TableId(type = IdType.AUTO)
+    private Long noticeId;
+
+    /**
+     * 类型
+     */
+    private Long noticeTypeId;
+
+    /**
+     * 标题
+     */
+    private String title;
+
+    /**
+     * 是否全部可见
+     */
+    private Boolean allVisibleFlag;
+
+    /**
+     * 是否定时发布
+     */
+    private Boolean scheduledPublishFlag;
+
+    /**
+     * 发布时间
+     */
+    private LocalDateTime publishTime;
+
+    /**
+     * 内容 纯文本
+     */
+    private String contentText;
+
+    /**
+     * 内容 html
+     */
+    private String contentHtml;
+
+    /**
+     * 附件
+     * 多个英文逗号分隔
+     */
+    private String attachment;
+
+    /**
+     * 页面浏览量
+     */
+    private Integer pageViewCount;
+
+    /**
+     * 用户浏览量
+     */
+    private Integer userViewCount;
+
+    /**
+     * 来源
+     */
+    private String source;
+
+    /**
+     * 作者
+     */
+    private String author;
+
+    /**
+     * 文号
+     */
+    private String documentNumber;
+
+    private Boolean deletedFlag;
+
+    private Long createUserId;
+
+    private LocalDateTime updateTime;
+
+    private LocalDateTime createTime;
+}

+ 40 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/entity/NoticeTypeEntity.java

@@ -0,0 +1,40 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 通知公告类型
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+@TableName("t_notice_type")
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class NoticeTypeEntity {
+
+    @TableId(type = IdType.AUTO)
+    private Long noticeTypeId;
+
+    /**
+     * 名称
+     */
+    private String noticeTypeName;
+
+
+    private LocalDateTime updateTime;
+
+    private LocalDateTime createTime;
+}

+ 77 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeAddForm.java

@@ -0,0 +1,77 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.form;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.json.deserializer.FileKeyVoDeserializer;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 通知公告 添加表单
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ * 
+ */
+@Data
+public class NoticeAddForm {
+
+    @Schema(description = "标题")
+    @NotBlank(message = "标题不能为空")
+    @Length(max = 200, message = "标题最多200字符")
+    private String title;
+
+    @Schema(description = "分类")
+    @NotNull(message = "分类不能为空")
+    private Long noticeTypeId;
+
+    @Schema(description = "是否全部可见")
+    @NotNull(message = "是否全部可见不能为空")
+    private Boolean allVisibleFlag;
+
+    @Schema(description = "是否定时发布")
+    @NotNull(message = "是否定时发布不能为空")
+    private Boolean scheduledPublishFlag;
+
+    @Schema(description = "发布时间")
+    @NotNull(message = "发布时间不能为空")
+    private LocalDateTime publishTime;
+
+    @Schema(description = "纯文本内容")
+    @NotNull(message = "文本内容不能为空")
+    private String contentText;
+
+    @Schema(description = "html内容")
+    @NotNull(message = "html内容不能为空")
+    private String contentHtml;
+
+    @Schema(description = "附件,多个英文逗号分隔|可选")
+    @Length(max = 1000, message = "最多1000字符")
+    @JsonDeserialize(using = FileKeyVoDeserializer.class)
+    private String attachment;
+
+    @Schema(description = "作者")
+    @NotBlank(message = "作者不能为空")
+    private String author;
+
+    @Schema(description = "来源")
+    @NotBlank(message = "标题不能为空")
+    private String source;
+
+    @Schema(description = "文号")
+    private String documentNumber;
+
+    @Schema(hidden = true)
+    private Long createUserId;
+
+    @Schema(description = "可见范围设置|可选")
+    @Valid
+    private List<NoticeVisibleRangeForm> visibleRangeList;
+}

+ 34 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeEmployeeQueryForm.java

@@ -0,0 +1,34 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.domain.PageParam;
+
+import java.time.LocalDate;
+
+/**
+ * 通知公告 员工查询表单
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+public class NoticeEmployeeQueryForm extends PageParam {
+
+    @Schema(description = "标题、作者、来源、文号")
+    private String keywords;
+
+    @Schema(description = "分类")
+    private Long noticeTypeId;
+
+    @Schema(description = "发布-开始时间")
+    private LocalDate publishTimeBegin;
+
+    @Schema(description = "未读标识")
+    private Boolean notViewFlag;
+
+    @Schema(description = "发布-截止时间")
+    private LocalDate publishTimeEnd;
+}

+ 47 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeQueryForm.java

@@ -0,0 +1,47 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.domain.PageParam;
+
+import java.time.LocalDate;
+
+/**
+ * 通知公告 管理查询表单
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+public class NoticeQueryForm extends PageParam {
+
+    @Schema(description = "分类")
+    private Long noticeTypeId;
+
+    @Schema(description = "标题、作者、来源")
+    private String keywords;
+
+    @Schema(description = "文号")
+    private String documentNumber;
+
+    @Schema(description = "创建人")
+    private Long createUserId;
+
+    @Schema(description = "删除标识")
+    private Boolean deletedFlag;
+
+    @Schema(description = "创建-开始时间")
+    private LocalDate createTimeBegin;
+
+    @Schema(description = "创建-截止时间")
+    private LocalDate createTimeEnd;
+
+    @Schema(description = "发布-开始时间")
+    private LocalDate publishTimeBegin;
+
+    @Schema(description = "发布-截止时间")
+    private LocalDate publishTimeEnd;
+
+}

+ 23 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeUpdateForm.java

@@ -0,0 +1,23 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 通知公告 更新表单
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+public class NoticeUpdateForm extends NoticeAddForm {
+
+    @Schema(description = "id")
+    @NotNull(message = "通知id不能为空")
+    private Long noticeId;
+
+}

+ 31 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeViewRecordQueryForm.java

@@ -0,0 +1,31 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.domain.PageParam;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 通知公告 阅读记录查询
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ * 
+ */
+@Data
+public class NoticeViewRecordQueryForm extends PageParam {
+
+    @Schema(description = "通知公告id")
+    @NotNull(message = "通知公告id不能为空")
+    private Long noticeId;
+
+    @Schema(description = "部门id")
+    private Long departmentId;
+
+    @Schema(description = "关键字")
+    private String keywords;
+
+
+}

+ 33 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/form/NoticeVisibleRangeForm.java

@@ -0,0 +1,33 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.form;
+
+import com.cloud.sa.admin.module.business.oa.notice.constant.NoticeVisibleRangeDataTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+import com.cloud.sa.base.common.validator.enumeration.CheckEnum;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 通知公告 可见范围数据
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ * 
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class NoticeVisibleRangeForm {
+
+    @SchemaEnum(NoticeVisibleRangeDataTypeEnum.class)
+    @CheckEnum(value = NoticeVisibleRangeDataTypeEnum.class, required = true, message = "数据类型错误")
+    private Integer dataType;
+
+    @Schema(description = "员工/部门id")
+    @NotNull(message = "员工/部门id不能为空")
+    private Long dataId;
+}

+ 83 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeDetailVO.java

@@ -0,0 +1,83 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.vo;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.json.serializer.FileKeyVoSerializer;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+/**
+ * 通知公告 详情
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+public class NoticeDetailVO {
+
+    @Schema(description = "id")
+    private Long noticeId;
+
+    @Schema(description = "标题")
+    private String title;
+
+    @Schema(description = "分类")
+    private Long noticeTypeId;
+
+    @Schema(description = "分类名称")
+    private Long noticeTypeName;
+
+    @Schema(description = "是否全部可见")
+    @NotNull(message = "是否全部可见不能为空")
+    private Boolean allVisibleFlag;
+
+    @Schema(description = "是否定时发布")
+    @NotNull(message = "是否定时发布不能为空")
+    private Boolean scheduledPublishFlag;
+
+    @Schema(description = "纯文本内容")
+    private String contentText;
+
+    @Schema(description = "html内容")
+    private String contentHtml;
+
+    @Schema(description = "附件")
+    @JsonSerialize(using = FileKeyVoSerializer.class)
+    private String attachment;
+
+    @Schema(description = "发布时间")
+    @NotNull(message = "发布时间不能为空")
+    private LocalDateTime publishTime;
+
+    @Schema(description = "作者")
+    @NotBlank(message = "作者不能为空")
+    private String author;
+
+    @Schema(description = "来源")
+    @NotBlank(message = "标题不能为空")
+    private String source;
+
+    @Schema(description = "文号")
+    private String documentNumber;
+
+    @Schema(description = "页面浏览量")
+    private Integer pageViewCount;
+
+    @Schema(description = "用户浏览量")
+    private Integer userViewCount;
+
+    @Schema(description = "创建人名称")
+    private Long createUserName;
+
+    @Schema(description = "创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "更新时间")
+    private LocalDateTime updateTime;
+
+}

+ 25 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeEmployeeVO.java

@@ -0,0 +1,25 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDate;
+
+/**
+ * 通知公告 员工查看
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+public class NoticeEmployeeVO extends NoticeVO {
+
+    @Schema(description = "是否查看")
+    private Boolean viewFlag;
+
+    @Schema(description = "发布日期")
+    private LocalDate publishDate;
+
+}

+ 23 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeTypeVO.java

@@ -0,0 +1,23 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 通知公告 类型
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ * 
+ */
+@Data
+public class NoticeTypeVO {
+
+    @Schema(description = "通知类型id")
+    private Long noticeTypeId;
+
+    @Schema(description = "通知类型-名称")
+    private String noticeTypeName;
+
+}

+ 34 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeUpdateFormVO.java

@@ -0,0 +1,34 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.vo;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.json.serializer.FileKeyVoSerializer;
+
+import java.util.List;
+
+/**
+ * 用于更新 【通知、公告】 的 VO 对象
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+public class NoticeUpdateFormVO extends NoticeVO {
+
+    @Schema(description = "纯文本内容")
+    private String contentText;
+
+    @Schema(description = "html内容")
+    private String contentHtml;
+
+    @Schema(description = "附件")
+    @JsonSerialize(using = FileKeyVoSerializer.class)
+    private String attachment;
+
+    @Schema(description = "可见范围")
+    private List<NoticeVisibleRangeVO> visibleRangeList;
+
+}

+ 72 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeVO.java

@@ -0,0 +1,72 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.time.LocalDateTime;
+
+
+/**
+ * 新闻、公告  VO
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+public class NoticeVO {
+
+    @Schema(description = "id")
+    private Long noticeId;
+
+    @Schema(description = "标题")
+    private String title;
+
+    @Schema(description = "分类")
+    private Long noticeTypeId;
+
+    @Schema(description = "分类名称")
+    private String noticeTypeName;
+
+    @Schema(description = "是否全部可见")
+    private Boolean allVisibleFlag;
+
+    @Schema(description = "是否定时发布")
+    private Boolean scheduledPublishFlag;
+
+    @Schema(description = "发布状态")
+    private Boolean publishFlag;
+
+    @Schema(description = "发布时间")
+    private LocalDateTime publishTime;
+
+    @Schema(description = "作者")
+    private String author;
+
+    @Schema(description = "来源")
+    private String source;
+
+    @Schema(description = "文号")
+    private String documentNumber;
+
+    @Schema(description = "页面浏览量")
+    private Integer pageViewCount;
+
+    @Schema(description = "用户浏览量")
+    private Integer userViewCount;
+
+    @Schema(description = "删除标识")
+    private Boolean deletedFlag;
+
+    @Schema(description = "创建人名称")
+    private String createUserName;
+
+    @Schema(description = "创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "更新时间")
+    private LocalDateTime updateTime;
+
+}

+ 48 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeViewRecordVO.java

@@ -0,0 +1,48 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 浏览记录 VO
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+public class NoticeViewRecordVO {
+
+    @Schema(description = "员工ID")
+    private Long employeeId;
+
+    @Schema(description = "员工姓名")
+    private String employeeName;
+
+    @Schema(description = "员工部门名称")
+    private String departmentName;
+
+    @Schema(description = "查看次数")
+    private Integer pageViewCount;
+
+    @Schema(description = "首次ip")
+    private String firstIp;
+
+    @Schema(description = "首次用户设备等标识")
+    private String firstUserAgent;
+
+    @Schema(description = "首次查看时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "最后一次 ip")
+    private String lastIp;
+
+    @Schema(description = "最后一次 用户设备等标识")
+    private String lastUserAgent;
+
+    @Schema(description = "最后一次查看时间")
+    private LocalDateTime updateTime;
+}

+ 28 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/domain/vo/NoticeVisibleRangeVO.java

@@ -0,0 +1,28 @@
+package com.cloud.sa.admin.module.business.oa.notice.domain.vo;
+
+import com.cloud.sa.admin.module.business.oa.notice.constant.NoticeVisibleRangeDataTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.cloud.sa.base.common.swagger.SchemaEnum;
+
+/**
+ * 新闻、公告 可见范围数据 VO
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Data
+public class NoticeVisibleRangeVO {
+
+    @SchemaEnum(NoticeVisibleRangeDataTypeEnum.class)
+    private Integer dataType;
+
+    @Schema(description = "员工/部门id")
+    private Long dataId;
+
+    @Schema(description = "员工/部门 名称")
+    private String dataName;
+
+}

+ 61 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/manager/NoticeManager.java

@@ -0,0 +1,61 @@
+package com.cloud.sa.admin.module.business.oa.notice.manager;
+
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeVisibleRangeForm;
+import com.cloud.sa.admin.module.business.oa.notice.dao.NoticeDao;
+import com.cloud.sa.admin.module.business.oa.notice.domain.entity.NoticeEntity;
+import com.cloud.sa.base.module.support.datatracer.constant.DataTracerTypeEnum;
+import com.cloud.sa.base.module.support.datatracer.service.DataTracerService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 通知、公告 manager
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Service
+public class NoticeManager {
+
+    @Resource
+    private NoticeDao noticeDao;
+
+    @Resource
+    private DataTracerService dataTracerService;
+
+    /**
+     * 保存
+     */
+    @Transactional(rollbackFor = Throwable.class)
+    public void save(NoticeEntity noticeEntity, List<NoticeVisibleRangeForm> visibleRangeFormList) {
+        noticeDao.insert(noticeEntity);
+        Long noticeId = noticeEntity.getNoticeId();
+        // 保存可见范围
+        if (CollectionUtils.isNotEmpty(visibleRangeFormList)) {
+            noticeDao.insertVisibleRange(noticeId, visibleRangeFormList);
+        }
+        dataTracerService.insert(noticeId, DataTracerTypeEnum.OA_NOTICE);
+    }
+
+    /**
+     * 更新
+     *
+     */
+    @Transactional(rollbackFor = Throwable.class)
+    public void update(NoticeEntity old, NoticeEntity noticeEntity, List<NoticeVisibleRangeForm> visibleRangeList) {
+        noticeDao.updateById(noticeEntity);
+        Long noticeId = noticeEntity.getNoticeId();
+        // 保存可见范围
+        if (CollectionUtils.isNotEmpty(visibleRangeList)) {
+            noticeDao.deleteVisibleRange(noticeId);
+            noticeDao.insertVisibleRange(noticeId, visibleRangeList);
+        }
+        dataTracerService.update(noticeId, DataTracerTypeEnum.OA_NOTICE, old, noticeEntity);
+    }
+}

+ 152 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/service/NoticeEmployeeService.java

@@ -0,0 +1,152 @@
+package com.cloud.sa.admin.module.business.oa.notice.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.oa.notice.constant.NoticeVisibleRangeDataTypeEnum;
+import com.cloud.sa.admin.module.business.oa.notice.dao.NoticeDao;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeEmployeeQueryForm;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeViewRecordQueryForm;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.*;
+import com.cloud.sa.admin.module.system.department.service.DepartmentService;
+import com.cloud.sa.admin.module.system.employee.domain.entity.EmployeeEntity;
+import com.cloud.sa.admin.module.system.employee.service.EmployeeService;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.util.BlinkBeanUtil;
+import com.cloud.sa.base.common.util.BlinkPageUtil;
+import com.google.common.collect.Lists;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+
+/**
+ * 员工查看 通知。公告
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ */
+@Service
+public class NoticeEmployeeService {
+
+    @Resource
+    private NoticeDao noticeDao;
+
+    @Resource
+    private NoticeService noticeService;
+
+    @Resource
+    private DepartmentService departmentService;
+
+    @Resource
+    private EmployeeService employeeService;
+
+    /**
+     * 查询我的 通知、公告清单
+     */
+    public ResponseDTO<PageResult<NoticeEmployeeVO>> queryList(Long requestEmployeeId, NoticeEmployeeQueryForm noticeEmployeeQueryForm) {
+        Page<?> page = BlinkPageUtil.convert2PageQuery(noticeEmployeeQueryForm);
+
+        List<Long> employeeDepartmentIdList = Lists.newArrayList();
+        EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId);
+        // 如果不是管理员 则获取请求人的 部门及其子部门
+        if (!employeeEntity.getAdministratorFlag() && employeeEntity.getDepartmentId() != null) {
+            employeeDepartmentIdList = departmentService.selfAndChildrenIdList(employeeEntity.getDepartmentId());
+        }
+
+        List<NoticeEmployeeVO> noticeList = null;
+        //只查询未读的
+        if (noticeEmployeeQueryForm.getNotViewFlag() != null && noticeEmployeeQueryForm.getNotViewFlag()) {
+            noticeList = noticeDao.queryEmployeeNotViewNotice(page,
+                    requestEmployeeId,
+                    noticeEmployeeQueryForm,
+                    employeeDepartmentIdList,
+                    false,
+                    employeeEntity.getAdministratorFlag(),
+                    NoticeVisibleRangeDataTypeEnum.DEPARTMENT.getValue(),
+                    NoticeVisibleRangeDataTypeEnum.EMPLOYEE.getValue());
+        } else {
+            // 查询全部
+            noticeList = noticeDao.queryEmployeeNotice(page,
+                    requestEmployeeId,
+                    noticeEmployeeQueryForm,
+                    employeeDepartmentIdList,
+                    false,
+                    employeeEntity.getAdministratorFlag(),
+                    NoticeVisibleRangeDataTypeEnum.DEPARTMENT.getValue(),
+                    NoticeVisibleRangeDataTypeEnum.EMPLOYEE.getValue());
+        }
+        // 设置发布日期
+        noticeList.forEach(notice -> notice.setPublishDate(notice.getPublishTime().toLocalDate()));
+
+        return ResponseDTO.ok(BlinkPageUtil.convert2PageResult(page, noticeList));
+    }
+
+
+    /**
+     * 查询我的 待查看的 通知、公告清单
+     */
+    public ResponseDTO<NoticeDetailVO> view(Long requestEmployeeId, Long noticeId, String ip, String userAgent) {
+        NoticeUpdateFormVO updateFormVO = noticeService.getUpdateFormVO(noticeId);
+        if (updateFormVO == null || Boolean.TRUE.equals(updateFormVO.getDeletedFlag())) {
+            return ResponseDTO.userErrorParam("通知公告不存在");
+        }
+
+        EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId);
+        if (!updateFormVO.getAllVisibleFlag() && !checkVisibleRange(updateFormVO.getVisibleRangeList(), requestEmployeeId, employeeEntity.getDepartmentId())) {
+            return ResponseDTO.userErrorParam("对不起,您没有权限查看内容");
+        }
+
+        NoticeDetailVO noticeDetailVO = BlinkBeanUtil.copy(updateFormVO, NoticeDetailVO.class);
+        long viewCount = noticeDao.viewRecordCount(noticeId, requestEmployeeId);
+        if (viewCount == 0) {
+            noticeDao.insertViewRecord(noticeId, requestEmployeeId, ip, userAgent, 1);
+            // 该员工对于这个通知是第一次查看 页面浏览量+1 用户浏览量+1
+            noticeDao.updateViewCount(noticeId, 1, 1);
+            noticeDetailVO.setPageViewCount(noticeDetailVO.getPageViewCount() + 1);
+            noticeDetailVO.setUserViewCount(noticeDetailVO.getUserViewCount() + 1);
+        } else {
+            noticeDao.updateViewRecord(noticeId, requestEmployeeId, ip, userAgent);
+            // 该员工对于这个通知不是第一次查看 页面浏览量+1 用户浏览量+0
+            noticeDao.updateViewCount(noticeId, 1, 0);
+            noticeDetailVO.setPageViewCount(noticeDetailVO.getPageViewCount() + 1);
+        }
+
+        return ResponseDTO.ok(noticeDetailVO);
+    }
+
+    /**
+     * 校验是否有查看权限的范围
+     */
+    public boolean checkVisibleRange(List<NoticeVisibleRangeVO> visibleRangeList, Long employeeId, Long departmentId) {
+        // 员工范围
+        boolean anyMatch = visibleRangeList.stream().anyMatch(e -> NoticeVisibleRangeDataTypeEnum.EMPLOYEE.equalsValue(e.getDataType()) && Objects.equals(e.getDataId(), employeeId));
+        if (anyMatch) {
+            return true;
+        }
+
+        //部门范围
+        List<Long> visibleDepartmentIdList = visibleRangeList.stream().filter(e -> NoticeVisibleRangeDataTypeEnum.DEPARTMENT.equalsValue(e.getDataType()))
+                .map(NoticeVisibleRangeVO::getDataId).collect(Collectors.toList());
+
+        for (Long visibleDepartmentId : visibleDepartmentIdList) {
+            List<Long> departmentIdList = departmentService.selfAndChildrenIdList(visibleDepartmentId);
+            if (departmentIdList.contains(departmentId)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 分页查询  查看记录
+     */
+    public PageResult<NoticeViewRecordVO> queryViewRecord(NoticeViewRecordQueryForm noticeViewRecordQueryForm) {
+        Page<?> page = BlinkPageUtil.convert2PageQuery(noticeViewRecordQueryForm);
+        List<NoticeViewRecordVO> noticeViewRecordList = noticeDao.queryNoticeViewRecordList(page, noticeViewRecordQueryForm);
+        return BlinkPageUtil.convert2PageResult(page, noticeViewRecordList);
+    }
+}

+ 235 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/service/NoticeService.java

@@ -0,0 +1,235 @@
+package com.cloud.sa.admin.module.business.oa.notice.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.cloud.sa.admin.module.business.oa.notice.constant.NoticeVisibleRangeDataTypeEnum;
+import com.google.common.collect.Maps;
+import com.cloud.sa.admin.module.business.oa.notice.dao.NoticeDao;
+import com.cloud.sa.admin.module.business.oa.notice.domain.entity.NoticeEntity;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeAddForm;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeQueryForm;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeUpdateForm;
+import com.cloud.sa.admin.module.business.oa.notice.domain.form.NoticeVisibleRangeForm;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.NoticeTypeVO;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.NoticeUpdateFormVO;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.NoticeVO;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.NoticeVisibleRangeVO;
+import com.cloud.sa.admin.module.business.oa.notice.manager.NoticeManager;
+import com.cloud.sa.admin.module.system.department.dao.DepartmentDao;
+import com.cloud.sa.admin.module.system.department.domain.entity.DepartmentEntity;
+import com.cloud.sa.admin.module.system.department.domain.vo.DepartmentVO;
+import com.cloud.sa.admin.module.system.department.service.DepartmentService;
+import com.cloud.sa.admin.module.system.employee.dao.EmployeeDao;
+import com.cloud.sa.admin.module.system.employee.domain.entity.EmployeeEntity;
+import com.cloud.sa.base.common.constant.StringConst;
+import com.cloud.sa.base.common.domain.PageResult;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.util.BlinkBeanUtil;
+import com.cloud.sa.base.common.util.BlinkPageUtil;
+import com.cloud.sa.base.module.support.datatracer.constant.DataTracerTypeEnum;
+import com.cloud.sa.base.module.support.datatracer.service.DataTracerService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 通知。公告 后台管理业务
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ * 
+ */
+@Service
+public class NoticeService {
+
+    @Resource
+    private NoticeDao noticeDao;
+
+    @Resource
+    private NoticeManager noticeManager;
+
+    @Resource
+    private EmployeeDao employeeDao;
+
+    @Resource
+    private DepartmentDao departmentDao;
+
+    @Resource
+    private DepartmentService departmentService;
+
+    @Resource
+    private NoticeTypeService noticeTypeService;
+
+    @Resource
+    private DataTracerService dataTracerService;
+
+    /**
+     * 查询 通知、公告
+     *
+     */
+    public PageResult<NoticeVO> query(NoticeQueryForm queryForm) {
+        Page<?> page = BlinkPageUtil.convert2PageQuery(queryForm);
+        List<NoticeVO> list = noticeDao.query(page, queryForm);
+        LocalDateTime now = LocalDateTime.now();
+        list.forEach(e -> e.setPublishFlag(e.getPublishTime().isBefore(now)));
+        return BlinkPageUtil.convert2PageResult(page, list);
+    }
+
+    /**
+     * 添加
+     */
+    public ResponseDTO<String> add(NoticeAddForm addForm) {
+        // 校验并获取可见范围
+        ResponseDTO<String> validate = this.checkAndBuildVisibleRange(addForm);
+        if (!validate.getOk()) {
+            return ResponseDTO.error(validate);
+        }
+
+        // build 资讯
+        NoticeEntity noticeEntity = BlinkBeanUtil.copy(addForm, NoticeEntity.class);
+        // 发布时间:不是定时发布时 默认为 当前
+        if (!addForm.getScheduledPublishFlag()) {
+            noticeEntity.setPublishTime(LocalDateTime.now());
+        }
+        // 保存数据
+        noticeManager.save(noticeEntity, addForm.getVisibleRangeList());
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 校验并返回可见范围
+     *
+     */
+    private ResponseDTO<String> checkAndBuildVisibleRange(NoticeAddForm form) {
+        // 校验资讯分类
+        NoticeTypeVO noticeType = noticeTypeService.getByNoticeTypeId(form.getNoticeTypeId());
+        if (noticeType == null) {
+            return ResponseDTO.userErrorParam("分类不存在");
+        }
+
+        if (form.getAllVisibleFlag()) {
+            return ResponseDTO.ok();
+        }
+
+        /*
+         * 校验可见范围
+         * 非全部可见时 校验选择的员工|部门
+         */
+        List<NoticeVisibleRangeForm> visibleRangeUpdateList = form.getVisibleRangeList();
+        if (CollectionUtils.isEmpty(visibleRangeUpdateList)) {
+            return ResponseDTO.userErrorParam("未设置可见范围");
+        }
+
+        // 校验可见范围-> 员工
+        List<Long> employeeIdList = visibleRangeUpdateList.stream()
+                .filter(e -> NoticeVisibleRangeDataTypeEnum.EMPLOYEE.equalsValue(e.getDataType()))
+                .map(NoticeVisibleRangeForm::getDataId)
+                .distinct().collect(Collectors.toList());
+        if (CollectionUtils.isNotEmpty(employeeIdList)) {
+            employeeIdList = employeeIdList.stream().distinct().collect(Collectors.toList());
+            List<Long> dbEmployeeIdList = employeeDao.selectBatchIds(employeeIdList).stream().map(EmployeeEntity::getEmployeeId).collect(Collectors.toList());
+            Collection<Long> subtract = CollectionUtils.subtract(employeeIdList, dbEmployeeIdList);
+            if (!subtract.isEmpty()) {
+                return ResponseDTO.userErrorParam("员工id不存在:" + subtract);
+            }
+        }
+
+        // 校验可见范围-> 部门
+        List<Long> deptIdList = visibleRangeUpdateList.stream()
+                .filter(e -> NoticeVisibleRangeDataTypeEnum.DEPARTMENT.equalsValue(e.getDataType()))
+                .map(NoticeVisibleRangeForm::getDataId)
+                .distinct().collect(Collectors.toList());
+        if (CollectionUtils.isNotEmpty(deptIdList)) {
+            deptIdList = deptIdList.stream().distinct().collect(Collectors.toList());
+            List<Long> dbDeptIdList = departmentDao.selectBatchIds(deptIdList).stream().map(DepartmentEntity::getDepartmentId).collect(Collectors.toList());
+            Collection<Long> subtract = CollectionUtils.subtract(deptIdList, dbDeptIdList);
+            if (!subtract.isEmpty()) {
+                return ResponseDTO.userErrorParam("部门id不存在:" + subtract);
+            }
+        }
+        return ResponseDTO.ok();
+    }
+
+
+    /**
+     * 更新
+     *
+     */
+    public ResponseDTO<String> update(NoticeUpdateForm updateForm) {
+
+        NoticeEntity oldNoticeEntity = noticeDao.selectById(updateForm.getNoticeId());
+        if (oldNoticeEntity == null) {
+            return ResponseDTO.userErrorParam("通知不存在");
+        }
+
+        // 校验并获取可见范围
+        ResponseDTO<String> res = this.checkAndBuildVisibleRange(updateForm);
+        if (!res.getOk()) {
+            return ResponseDTO.error(res);
+        }
+
+        // 更新
+        NoticeEntity noticeEntity = BlinkBeanUtil.copy(updateForm, NoticeEntity.class);
+        noticeManager.update(oldNoticeEntity, noticeEntity, updateForm.getVisibleRangeList());
+        return ResponseDTO.ok();
+    }
+
+
+    /**
+     * 删除
+     *
+     */
+    public ResponseDTO<String> delete(Long noticeId) {
+        NoticeEntity noticeEntity = noticeDao.selectById(noticeId);
+        if (null == noticeEntity || noticeEntity.getDeletedFlag()) {
+            return ResponseDTO.userErrorParam("通知公告不存在");
+        }
+        // 更新删除状态
+        noticeDao.updateDeletedFlag(noticeId);
+        dataTracerService.delete(noticeId, DataTracerTypeEnum.OA_NOTICE);
+        return ResponseDTO.ok();
+    }
+
+    /**
+     * 获取更新表单用的详情
+     */
+    public NoticeUpdateFormVO getUpdateFormVO(Long noticeId) {
+        NoticeEntity noticeEntity = noticeDao.selectById(noticeId);
+        if (null == noticeEntity) {
+            return null;
+        }
+
+        NoticeUpdateFormVO updateFormVO = BlinkBeanUtil.copy(noticeEntity, NoticeUpdateFormVO.class);
+        if (!updateFormVO.getAllVisibleFlag()) {
+            List<NoticeVisibleRangeVO> noticeVisibleRangeList = noticeDao.queryVisibleRange(noticeId);
+            List<Long> employeeIdList = noticeVisibleRangeList.stream().filter(e -> NoticeVisibleRangeDataTypeEnum.EMPLOYEE.getValue().equals(e.getDataType()))
+                    .map(NoticeVisibleRangeVO::getDataId)
+                    .collect(Collectors.toList());
+
+            Map<Long, EmployeeEntity> employeeMap = null;
+            if (CollectionUtils.isNotEmpty(employeeIdList)) {
+                employeeMap = employeeDao.selectBatchIds(employeeIdList).stream().collect(Collectors.toMap(EmployeeEntity::getEmployeeId, Function.identity()));
+            } else {
+                employeeMap = Maps.newHashMap();
+            }
+            for (NoticeVisibleRangeVO noticeVisibleRange : noticeVisibleRangeList) {
+                if (noticeVisibleRange.getDataType().equals(NoticeVisibleRangeDataTypeEnum.EMPLOYEE.getValue())) {
+                    EmployeeEntity employeeEntity = employeeMap.get(noticeVisibleRange.getDataId());
+                    noticeVisibleRange.setDataName(employeeEntity == null ? StringConst.EMPTY : employeeEntity.getActualName());
+                } else {
+                    DepartmentVO departmentVO = departmentService.getDepartmentById(noticeVisibleRange.getDataId());
+                    noticeVisibleRange.setDataName(departmentVO == null ? StringConst.EMPTY : departmentVO.getName());
+                }
+            }
+            updateFormVO.setVisibleRangeList(noticeVisibleRangeList);
+        }
+        return updateFormVO;
+    }
+}

+ 86 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/business/oa/notice/service/NoticeTypeService.java

@@ -0,0 +1,86 @@
+package com.cloud.sa.admin.module.business.oa.notice.service;
+
+import cn.hutool.core.util.StrUtil;
+import com.cloud.sa.admin.module.business.oa.notice.dao.NoticeTypeDao;
+import com.cloud.sa.admin.module.business.oa.notice.domain.entity.NoticeTypeEntity;
+import com.cloud.sa.admin.module.business.oa.notice.domain.vo.NoticeTypeVO;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import com.cloud.sa.base.common.util.BlinkBeanUtil;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * 通知。公告 类型
+ *
+ * @Author 畅联云: admin
+ * @Date 2022-08-12 21:40:39
+
+ *
+ */
+@Service
+public class NoticeTypeService {
+
+    @Resource
+    private NoticeTypeDao noticeTypeDao;
+
+    /**
+     * 查询全部
+     * @return
+     */
+    public List<NoticeTypeVO> getAll() {
+        return BlinkBeanUtil.copyList(noticeTypeDao.selectList(null), NoticeTypeVO.class);
+    }
+
+    public NoticeTypeVO getByNoticeTypeId(Long noticceTypeId) {
+        return BlinkBeanUtil.copy(noticeTypeDao.selectById(noticceTypeId), NoticeTypeVO.class);
+    }
+
+    public synchronized ResponseDTO<String> add(String name) {
+        if (StrUtil.isBlank(name)) {
+            return ResponseDTO.userErrorParam("类型名称不能为空");
+        }
+
+        List<NoticeTypeEntity> noticeTypeEntityList = noticeTypeDao.selectList(null);
+        if (!CollectionUtils.isEmpty(noticeTypeEntityList)) {
+            boolean exist = noticeTypeEntityList.stream().map(NoticeTypeEntity::getNoticeTypeName).collect(Collectors.toSet()).contains(name);
+            if (exist) {
+                return ResponseDTO.userErrorParam("类型名称已经存在");
+            }
+        }
+        noticeTypeDao.insert(NoticeTypeEntity.builder().noticeTypeName(name).build());
+        return ResponseDTO.ok();
+    }
+
+    public synchronized ResponseDTO<String> update(Long noticeTypeId, String name) {
+        if (StrUtil.isBlank(name)) {
+            return ResponseDTO.userErrorParam("类型名称不能为空");
+        }
+
+        NoticeTypeEntity noticeTypeEntity = noticeTypeDao.selectById(noticeTypeId);
+        if (noticeTypeEntity == null) {
+            return ResponseDTO.userErrorParam("类型名称不存在");
+        }
+
+        List<NoticeTypeEntity> noticeTypeEntityList = noticeTypeDao.selectList(null);
+        if (!CollectionUtils.isEmpty(noticeTypeEntityList)) {
+            Optional<NoticeTypeEntity> optionalNoticeTypeEntity = noticeTypeEntityList.stream().filter(e -> e.getNoticeTypeName().equals(name)).findFirst();
+            if (optionalNoticeTypeEntity.isPresent() && !optionalNoticeTypeEntity.get().getNoticeTypeId().equals(noticeTypeId)) {
+                return ResponseDTO.userErrorParam("类型名称已经存在");
+            }
+        }
+        noticeTypeEntity.setNoticeTypeName(name);
+        noticeTypeDao.updateById(noticeTypeEntity);
+        return ResponseDTO.ok();
+    }
+
+    public synchronized ResponseDTO<String> delete(Long noticeTypeId) {
+        noticeTypeDao.deleteById(noticeTypeId);
+        return ResponseDTO.ok();
+    }
+
+}

+ 49 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/DataScope.java

@@ -0,0 +1,49 @@
+package com.cloud.sa.admin.module.system.datascope;
+
+
+import com.cloud.sa.admin.module.system.datascope.constant.DataScopeTypeEnum;
+import com.cloud.sa.admin.module.system.datascope.constant.DataScopeWhereInTypeEnum;
+import com.cloud.sa.admin.module.system.datascope.strategy.AbstractDataScopeStrategy;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 数据范围
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-03-18 20:59:17
+
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface DataScope {
+
+    DataScopeTypeEnum dataScopeType() ;
+
+    DataScopeWhereInTypeEnum whereInType() default DataScopeWhereInTypeEnum.EMPLOYEE;
+
+    /**
+     * DataScopeWhereInTypeEnum.CUSTOM_STRATEGY类型 才可使用joinSqlImplClazz属性
+     */
+    Class<? extends AbstractDataScopeStrategy> joinSqlImplClazz()  default AbstractDataScopeStrategy.class;
+
+    /**
+     * 多个参数已逗号分隔,本属性主要用于joinSqlImplClazz 实现类跟进参数进行不同的范围控制,如不使用CUSTOM_STRATEGY,可不做配置
+     */
+    String paramName() default "";
+    /**
+     *
+     * 第几个where 条件 从0开始
+     */
+    int whereIndex() default 0;
+
+    /**
+     * DataScopeWhereInTypeEnum为CUSTOM_STRATEGY类型时,此属性无效
+     */
+    String joinSql() default "";
+
+}

+ 37 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/DataScopeController.java

@@ -0,0 +1,37 @@
+package com.cloud.sa.admin.module.system.datascope;
+
+import com.cloud.sa.admin.constant.AdminSwaggerTagConst;
+import com.cloud.sa.admin.module.system.datascope.domain.DataScopeAndViewTypeVO;
+import com.cloud.sa.admin.module.system.datascope.service.DataScopeService;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import com.cloud.sa.base.common.domain.ResponseDTO;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 查询支持的数据范围类型
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-03-18 20:59:17
+
+ * 
+ */
+@RestController
+@Tag(name = AdminSwaggerTagConst.System.SYSTEM_DATA_SCOPE)
+public class DataScopeController {
+
+    @Resource
+    private DataScopeService dataScopeService;
+
+    @Operation(summary = "获取当前系统所配置的所有数据范围 @author admin")
+    @GetMapping("/dataScope/list")
+    public ResponseDTO<List<DataScopeAndViewTypeVO>> dataScopeList() {
+        return dataScopeService.dataScopeList();
+    }
+
+
+}

+ 185 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/MyBatisPlugin.java

@@ -0,0 +1,185 @@
+package com.cloud.sa.admin.module.system.datascope;
+
+import cn.hutool.core.util.StrUtil;
+import com.cloud.sa.admin.module.system.datascope.domain.DataScopeSqlConfig;
+import com.cloud.sa.admin.module.system.datascope.service.DataScopeSqlConfigService;
+import com.google.common.collect.Maps;
+import com.cloud.sa.base.common.domain.DataScopePlugin;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.mapping.*;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Plugin;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * mybaits sql 拦截
+ *
+ * @Author 云畅联: admin
+ * @Date 2022-03-18 20:59:17
+
+ *
+ */
+@Intercepts({@Signature(type = org.apache.ibatis.executor.Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
+@Component
+public class MyBatisPlugin extends DataScopePlugin {
+
+    @Resource
+    private ApplicationContext applicationContext;
+
+    @Override
+    public Object intercept(Invocation invocation) throws Throwable {
+
+        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
+        Object parameter = invocation.getArgs()[1];
+
+        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
+        String originalSql = boundSql.getSql().trim();
+        String id = mappedStatement.getId();
+        List<String> methodStrList = StrUtil.split(id, ".");
+        String path = methodStrList.get(methodStrList.size() - 2) + "." + methodStrList.get(methodStrList.size() - 1);
+        DataScopeSqlConfigService dataScopeSqlConfigService = this.dataScopeSqlConfigService();
+        if (dataScopeSqlConfigService == null) {
+            return invocation.proceed();
+        }
+        DataScopeSqlConfig sqlConfigDTO = dataScopeSqlConfigService.getSqlConfig(path);
+        if (sqlConfigDTO != null) {
+            Map<String, Object> paramMap = this.getParamList(sqlConfigDTO.getParamName(), parameter);
+            BoundSql newBoundSql = copyFromBoundSql(mappedStatement, boundSql, this.joinSql(originalSql, paramMap, sqlConfigDTO));
+            ParameterMap map = mappedStatement.getParameterMap();
+            MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql), map);
+            invocation.getArgs()[0] = newMs;
+        }
+
+        Object obj = invocation.proceed();
+        return obj;
+    }
+
+
+    private Map<String, Object> getParamList(String paramName, Object parameter) {
+        Map<String, Object> paramMap = Maps.newHashMap();
+        if (StringUtils.isEmpty(paramName)) {
+            return paramMap;
+        }
+        if (parameter == null) {
+            return paramMap;
+        }
+        if (parameter instanceof Map) {
+            String[] paramNameArray = paramName.split(",");
+            Map<?, ?> parameterMap = (Map) parameter;
+            for (String param : paramNameArray) {
+                if(parameterMap.containsKey(param)){
+                    paramMap.put(param, parameterMap.get(param));
+                }
+            }
+        }
+        return paramMap;
+    }
+
+    private String joinSql(String sql, Map<String, Object> paramMap, DataScopeSqlConfig sqlConfigDTO) {
+        if (null == sqlConfigDTO) {
+            return sql;
+        }
+        String appendSql = this.dataScopeSqlConfigService().getJoinSql(paramMap, sqlConfigDTO);
+        if (StringUtils.isEmpty(appendSql)) {
+            return sql;
+        }
+        Integer appendSqlWhereIndex = sqlConfigDTO.getWhereIndex();
+        String where = "where";
+        String order = "order by";
+        String group = "group by";
+        int whereIndex = StringUtils.ordinalIndexOf(sql.toLowerCase(), where, appendSqlWhereIndex + 1);
+        int orderIndex = sql.toLowerCase().indexOf(order);
+        int groupIndex = sql.toLowerCase().indexOf(group);
+        if (whereIndex > -1) {
+            String subSql = sql.substring(0, whereIndex + where.length() + 1);
+            subSql = subSql + " " + appendSql + " AND " + sql.substring(whereIndex + where.length() + 1);
+            return subSql;
+        }
+
+        if (groupIndex > -1) {
+            String subSql = sql.substring(0, groupIndex);
+            subSql = subSql + " where " + appendSql + " " + sql.substring(groupIndex);
+            return subSql;
+        }
+        if (orderIndex > -1) {
+            String subSql = sql.substring(0, orderIndex);
+            subSql = subSql + " where " + appendSql + " " + sql.substring(orderIndex);
+            return subSql;
+        }
+        sql += " where " + appendSql;
+        return sql;
+    }
+
+    public DataScopeSqlConfigService dataScopeSqlConfigService() {
+        return (DataScopeSqlConfigService) applicationContext.getBean("dataScopeSqlConfigService");
+    }
+
+    public class BoundSqlSqlSource implements SqlSource {
+
+        BoundSql boundSql;
+
+        public BoundSqlSqlSource(BoundSql boundSql) {
+            this.boundSql = boundSql;
+        }
+
+        @Override
+        public BoundSql getBoundSql(Object parameterObject) {
+            return boundSql;
+        }
+    }
+
+    /**
+     * 复制MappedStatement对象
+     */
+    private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource, ParameterMap parameterMap) {
+
+        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
+        builder.resource(ms.getResource());
+        builder.fetchSize(ms.getFetchSize());
+        builder.statementType(ms.getStatementType());
+        builder.keyGenerator(ms.getKeyGenerator());
+        builder.timeout(ms.getTimeout());
+        builder.parameterMap(parameterMap);
+        builder.resultMaps(ms.getResultMaps());
+        builder.resultSetType(ms.getResultSetType());
+        builder.cache(ms.getCache());
+        builder.flushCacheRequired(ms.isFlushCacheRequired());
+        builder.useCache(ms.isUseCache());
+        return builder.build();
+    }
+
+    /**
+     * 复制BoundSql对象
+     */
+    private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql) {
+        BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
+        for (ParameterMapping mapping : boundSql.getParameterMappings()) {
+            String prop = mapping.getProperty();
+            if (boundSql.hasAdditionalParameter(prop)) {
+                newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
+            }
+        }
+        return newBoundSql;
+    }
+
+    @Override
+    public Object plugin(Object arg0) {
+        return Plugin.wrap(arg0, this);
+    }
+
+    @Override
+    public void setProperties(Properties arg0) {
+
+    }
+
+}

+ 55 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/constant/DataScopeTypeEnum.java

@@ -0,0 +1,55 @@
+package com.cloud.sa.admin.module.system.datascope.constant;
+
+import com.cloud.sa.base.common.enumeration.BaseEnum;
+
+/**
+ * 数据范围 类型
+ *
+ * @Author 云畅联: admin
+ * @Date 2020/11/28  20:59:17
+
+ *
+ */
+public enum DataScopeTypeEnum implements BaseEnum {
+
+    /**
+     * 系统通知
+     */
+    NOTICE(1, 20, "系统通知", "系统通知数据范围"),
+    ;
+
+    private final Integer value;
+
+    private final Integer sort;
+
+    private final String name;
+
+    private final String desc;
+
+    DataScopeTypeEnum(Integer value, Integer sort, String name, String desc) {
+        this.value = value;
+        this.sort = sort;
+        this.name = name;
+        this.desc = desc;
+    }
+
+    @Override
+    public Integer getValue() {
+        return value;
+    }
+
+    public Integer getSort() {
+        return sort;
+    }
+
+    @Override
+    public String getDesc() {
+        return desc;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+
+}

+ 64 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/constant/DataScopeViewTypeEnum.java

@@ -0,0 +1,64 @@
+package com.cloud.sa.admin.module.system.datascope.constant;
+
+
+import com.cloud.sa.base.common.enumeration.BaseEnum;
+
+
+/**
+ * 数据范围 种类
+ *
+ * @Author 云畅联: admin
+ * @Date 2020/11/28  20:59:17
+
+ *
+ */
+public enum DataScopeViewTypeEnum implements BaseEnum {
+
+    /**
+     * 本人
+     */
+    ME(0, 0, "本人"),
+
+    /**
+     * 部门
+     */
+    DEPARTMENT(1, 5, "本部门"),
+
+    /**
+     * 本部门及下属子部门
+     */
+    DEPARTMENT_AND_SUB(2, 10, "本部门及下属子部门"),
+
+    /**
+     * 全部
+     */
+    ALL(10, 100, "全部");
+
+
+
+    private final Integer value;
+    private final Integer level;
+    private final String desc;
+
+    DataScopeViewTypeEnum(Integer value, Integer level, String desc) {
+        this.value = value;
+        this.level = level;
+        this.desc = desc;
+    }
+
+    @Override
+    public Integer getValue() {
+        return value;
+    }
+
+    public Integer getLevel() {
+        return level;
+    }
+
+    @Override
+    public String getDesc() {
+        return desc;
+    }
+
+
+}

+ 50 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/constant/DataScopeWhereInTypeEnum.java

@@ -0,0 +1,50 @@
+package com.cloud.sa.admin.module.system.datascope.constant;
+
+
+import com.cloud.sa.base.common.enumeration.BaseEnum;
+
+/**
+ * 数据范围 sql where
+ *
+ * @Author 云畅联: admin
+ * @Date 2020/11/28  20:59:17
+
+ *
+ */
+public enum DataScopeWhereInTypeEnum implements BaseEnum {
+
+    /**
+     * 以员工IN
+     */
+    EMPLOYEE(0, "以员工IN"),
+
+    /**
+     * 以部门IN
+     */
+    DEPARTMENT(1, "以部门IN"),
+
+    /**
+     * 自定义策略
+     */
+    CUSTOM_STRATEGY(2, "自定义策略");
+
+    private final Integer value;
+    private final String desc;
+
+    DataScopeWhereInTypeEnum(Integer value, String desc) {
+        this.value = value;
+        this.desc = desc;
+    }
+
+    @Override
+    public Integer getValue() {
+        return value;
+    }
+
+    @Override
+    public String getDesc() {
+        return desc;
+    }
+
+
+}

+ 34 - 0
bound-link-api/blink-admin/src/main/java/com/cloud/sa/admin/module/system/datascope/domain/DataScopeAndViewTypeVO.java

@@ -0,0 +1,34 @@
+package com.cloud.sa.admin.module.system.datascope.domain;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 数据范围
+ *
+ * @Author 云畅联: admin
+ * @Date 2020/11/28  20:59:17
+
+ * 
+ */
+@Data
+public class DataScopeAndViewTypeVO {
+
+    @Schema(description = "数据范围类型")
+    private Integer dataScopeType;
+
+    @Schema(description = "数据范围名称")
+    private String dataScopeTypeName;
+
+    @Schema(description = "描述")
+    private String dataScopeTypeDesc;
+
+    @Schema(description = "顺序")
+    private Integer dataScopeTypeSort;
+
+    @Schema(description = "可见范围列表")
+    private List<DataScopeViewTypeVO> viewTypeList;
+
+}

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff