瀏覽代碼

代码结构优化

unknown 3 年之前
當前提交
699bd62cc1
共有 100 個文件被更改,包括 9599 次插入0 次删除
  1. 34 0
      .gitignore
  2. 277 0
      pom.xml
  3. 79 0
      saas-account/pom.xml
  4. 27 0
      saas-account/src/main/java/com/persagy/AccountServerApplication.java
  5. 37 0
      saas-account/src/main/java/com/persagy/person/aop/GlobalExceptionHandler.java
  6. 51 0
      saas-account/src/main/java/com/persagy/person/config/ApplicationProperties.java
  7. 81 0
      saas-account/src/main/java/com/persagy/person/config/RabbitMQConfig.java
  8. 83 0
      saas-account/src/main/java/com/persagy/person/config/SpringMVCConfig.java
  9. 301 0
      saas-account/src/main/java/com/persagy/person/controller/SaasAccountController.java
  10. 198 0
      saas-account/src/main/java/com/persagy/person/controller/SaasAccountProjectController.java
  11. 98 0
      saas-account/src/main/java/com/persagy/person/controller/SaasAccountRoleController.java
  12. 225 0
      saas-account/src/main/java/com/persagy/person/controller/SaasAreaController.java
  13. 156 0
      saas-account/src/main/java/com/persagy/person/controller/SaasFunctionController.java
  14. 158 0
      saas-account/src/main/java/com/persagy/person/controller/SaasGroupController.java
  15. 225 0
      saas-account/src/main/java/com/persagy/person/controller/SaasLoginController.java
  16. 168 0
      saas-account/src/main/java/com/persagy/person/controller/SaasMenuController.java
  17. 348 0
      saas-account/src/main/java/com/persagy/person/controller/SaasProjectController.java
  18. 226 0
      saas-account/src/main/java/com/persagy/person/controller/SaasRoleController.java
  19. 99 0
      saas-account/src/main/java/com/persagy/person/controller/SaasRoleMenuController.java
  20. 135 0
      saas-account/src/main/java/com/persagy/person/controller/UpgradeController.java
  21. 169 0
      saas-account/src/main/java/com/persagy/person/manage/SaasAccountHandler.java
  22. 370 0
      saas-account/src/main/java/com/persagy/person/manage/SaasAreaProjectHandler.java
  23. 197 0
      saas-account/src/main/java/com/persagy/person/manage/SaasAuthHandler.java
  24. 213 0
      saas-account/src/main/java/com/persagy/person/manage/SaasGroupProjectHandler.java
  25. 144 0
      saas-account/src/main/java/com/persagy/person/manage/SaasProjectExcelDataHandler.java
  26. 170 0
      saas-account/src/main/java/com/persagy/person/manage/SaasProjectSheetWriteHandler.java
  27. 247 0
      saas-account/src/main/java/com/persagy/person/manage/SaasRoleMenuHandler.java
  28. 32 0
      saas-account/src/main/java/com/persagy/person/mapper/SaasAccountMapper.java
  29. 49 0
      saas-account/src/main/java/com/persagy/person/mapper/SaasAccountProjectMapper.java
  30. 42 0
      saas-account/src/main/java/com/persagy/person/mapper/SaasAccountRoleMapper.java
  31. 30 0
      saas-account/src/main/java/com/persagy/person/mapper/SaasAreaMapper.java
  32. 43 0
      saas-account/src/main/java/com/persagy/person/mapper/SaasFunctionMapper.java
  33. 39 0
      saas-account/src/main/java/com/persagy/person/mapper/SaasGroupMapper.java
  34. 39 0
      saas-account/src/main/java/com/persagy/person/mapper/SaasMenuMapper.java
  35. 88 0
      saas-account/src/main/java/com/persagy/person/mapper/SaasProjectMapper.java
  36. 30 0
      saas-account/src/main/java/com/persagy/person/mapper/SaasRoleMapper.java
  37. 49 0
      saas-account/src/main/java/com/persagy/person/mapper/SaasRoleMenuMapper.java
  38. 29 0
      saas-account/src/main/java/com/persagy/person/mq/CommonConfirmCallback.java
  39. 60 0
      saas-account/src/main/java/com/persagy/person/mq/CommonTopicProducer.java
  40. 411 0
      saas-account/src/main/java/com/persagy/person/pojo/dto/SaasAccount.java
  41. 112 0
      saas-account/src/main/java/com/persagy/person/pojo/dto/SaasAccountProject.java
  42. 133 0
      saas-account/src/main/java/com/persagy/person/pojo/dto/SaasAccountRole.java
  43. 235 0
      saas-account/src/main/java/com/persagy/person/pojo/dto/SaasArea.java
  44. 213 0
      saas-account/src/main/java/com/persagy/person/pojo/dto/SaasFunction.java
  45. 248 0
      saas-account/src/main/java/com/persagy/person/pojo/dto/SaasGroup.java
  46. 274 0
      saas-account/src/main/java/com/persagy/person/pojo/dto/SaasMenu.java
  47. 327 0
      saas-account/src/main/java/com/persagy/person/pojo/dto/SaasProject.java
  48. 229 0
      saas-account/src/main/java/com/persagy/person/pojo/dto/SaasRole.java
  49. 112 0
      saas-account/src/main/java/com/persagy/person/pojo/dto/SaasRoleMenu.java
  50. 28 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/BaseGroupVO.java
  51. 29 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/BaseUserVO.java
  52. 98 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountCreateVO.java
  53. 33 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountGroupVO.java
  54. 44 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountLoginVO.java
  55. 36 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountPageVO.java
  56. 39 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountQueryByNameVO.java
  57. 66 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountQueryVO.java
  58. 49 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/area/SaasAreaCreateVO.java
  59. 31 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/area/SaasAreaDeleteVO.java
  60. 46 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/area/SaasAreaQueryVO.java
  61. 39 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/AccountAreaProjectResetVO.java
  62. 33 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/AccountAreaResetVO.java
  63. 37 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/AccountProjectResetVO.java
  64. 34 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountProjectBatchVO.java
  65. 34 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountProjectCreateVO.java
  66. 35 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountProjectPageVO.java
  67. 39 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountProjectQueryVO.java
  68. 40 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountRoleBatchVO.java
  69. 33 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountRoleCreateVO.java
  70. 49 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountRoleQueryVO.java
  71. 31 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountRoleVO.java
  72. 32 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasMenuFunctionVO.java
  73. 40 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasRoleMenuBatchVO.java
  74. 39 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasRoleMenuCreateVO.java
  75. 34 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasRoleMenuQueryVO.java
  76. 54 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/function/SaasFunctionCreateVO.java
  77. 31 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/function/SaasFunctionDeleteVO.java
  78. 43 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/function/SaasFunctionQueryVO.java
  79. 44 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/group/SaasGroupCreateVO.java
  80. 44 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/group/SaasGroupQueryVO.java
  81. 65 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/menu/SaasMenuCreateVO.java
  82. 31 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/menu/SaasMenuDeleteVO.java
  83. 37 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/menu/SaasMenuQueryVO.java
  84. 38 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/project/SaasProjectAreaUpdateVO.java
  85. 71 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/project/SaasProjectCreateVO.java
  86. 113 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/project/SaasProjectExcel.java
  87. 36 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/project/SaasProjectPageVO.java
  88. 70 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/project/SaasProjectQueryVO.java
  89. 53 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/role/SaasRoleCreateVO.java
  90. 34 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/role/SaasRoleDeleteVO.java
  91. 36 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/role/SaasRolePageVO.java
  92. 37 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/role/SaasRoleQueryByNameVO.java
  93. 57 0
      saas-account/src/main/java/com/persagy/person/pojo/vo/role/SaasRoleQueryVO.java
  94. 54 0
      saas-account/src/main/java/com/persagy/person/service/ISaasAccountProjectService.java
  95. 49 0
      saas-account/src/main/java/com/persagy/person/service/ISaasAccountRoleService.java
  96. 67 0
      saas-account/src/main/java/com/persagy/person/service/ISaasAccountService.java
  97. 58 0
      saas-account/src/main/java/com/persagy/person/service/ISaasAreaService.java
  98. 37 0
      saas-account/src/main/java/com/persagy/person/service/ISaasFunctionService.java
  99. 52 0
      saas-account/src/main/java/com/persagy/person/service/ISaasGroupService.java
  100. 0 0
      saas-account/src/main/java/com/persagy/person/service/ISaasMenuService.java

+ 34 - 0
.gitignore

@@ -0,0 +1,34 @@
+# IntelliJ project files
+.idea/
+*.iml
+out
+gen
+
+# Visual Studio Code
+.history/
+
+# Maven
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+!/.mvn/wrapper/maven-wrapper.jar
+
+# Eclipse
+.classpath
+.settings/
+.project
+.factorypath
+.springBeans
+*.log
+*.dat
+
+# System related
+*.DS_Store
+Thumbs.db
+.gitignore

+ 277 - 0
pom.xml

@@ -0,0 +1,277 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	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>
+	<groupId>com.persagy</groupId>
+	<artifactId>saas-platform</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+	<packaging>pom</packaging>
+
+
+	<properties>
+		<!-- java版本 -->
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<java.encoding>UTF-8</java.encoding>
+		<java.version>8</java.version>
+		<java.source.version>1.8</java.source.version>
+		<java.target.version>1.8</java.target.version>
+
+		<!-- spring版本依赖 -->
+		<integrated-platform.version>1.0.0</integrated-platform.version>
+		<spring-boot-dependencies.version>2.1.14.RELEASE</spring-boot-dependencies.version>
+		<spring-cloud-dependencies.version>Greenwich.SR6</spring-cloud-dependencies.version>
+		<mybatis-spring-boot-starter.version>1.3.2</mybatis-spring-boot-starter.version>
+
+		<!-- 三方jar依赖 -->
+		<mybatis-plus.version>3.3.1</mybatis-plus.version>
+		<guava.version>20.0</guava.version>
+
+		<!-- maven依赖 -->
+		<maven.compiler.version>3.8.0</maven.compiler.version>
+		<maven.surefire.version>2.22.1</maven.surefire.version>
+		<maven.source.version>3.0.1</maven.source.version>
+		<maven.javadoc.version>3.0.1</maven.javadoc.version>
+		<maven.gpg.version>1.6</maven.gpg.version>
+		<maven.jacoco.version>0.8.3</maven.jacoco.version>
+		<maven.jar.version>3.1.0</maven.jar.version>
+		<maven.pmd.version>3.8</maven.pmd.version>
+
+	</properties>
+
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>com.persagy</groupId>
+				<artifactId>integrated-platform</artifactId>
+				<version>${integrated-platform.version}</version>
+				<type>pom</type>
+				<scope>import</scope>
+			</dependency>
+			
+			<!-- saas-common -->
+			<dependency>
+				<groupId>com.persagy</groupId>
+				<artifactId>saas-common</artifactId>
+				<version>${project.version}</version>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
+	<!-- 公共依赖 -->
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+		</dependency>
+
+		<!--需要引入该jar才能使bootstrap配置文件生效 -->
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-context</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-configuration-processor</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-pmd-plugin</artifactId>
+				<version>${maven.pmd.version}</version>
+				<configuration>
+					<sourceEncoding>${project.build.sourceEncoding}</sourceEncoding>
+					<minimumPriority>1</minimumPriority>
+					<excludeRoots>
+						<excludeRoot>com/alibaba/csp/sentinel/benchmark</excludeRoot>
+					</excludeRoots>
+					<excludes>
+						<exclude>**/*_jmhTest.java</exclude>
+					</excludes>
+					<printFailingErrors>true</printFailingErrors>
+					<rulesets>
+						<ruleset>rulesets/java/ali-comment.xml</ruleset>
+						<ruleset>rulesets/java/ali-concurrent.xml</ruleset>
+						<ruleset>rulesets/java/ali-constant.xml</ruleset>
+						<ruleset>rulesets/java/ali-exception.xml</ruleset>
+						<ruleset>rulesets/java/ali-flowcontrol.xml</ruleset>
+						<ruleset>rulesets/java/ali-naming.xml</ruleset>
+						<ruleset>rulesets/java/ali-oop.xml</ruleset>
+						<ruleset>rulesets/java/ali-orm.xml</ruleset>
+						<ruleset>rulesets/java/ali-other.xml</ruleset>
+						<ruleset>rulesets/java/ali-set.xml</ruleset>
+					</rulesets>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>verify</phase>
+						<goals>
+							<goal>check</goal>
+						</goals>
+					</execution>
+				</executions>
+				<dependencies>
+					<dependency>
+						<groupId>com.alibaba.p3c</groupId>
+						<artifactId>p3c-pmd</artifactId>
+						<version>1.3.6</version>
+					</dependency>
+				</dependencies>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>${maven.compiler.version}</version>
+				<configuration>
+					<source>${java.source.version}</source>
+					<target>${java.target.version}</target>
+					<encoding>${java.encoding}</encoding>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<configuration>
+					<!-- CircleCI build workaround -->
+					<argLine>@{argLine} -Xms1024m -Xmx2048m</argLine>
+					<argLine>-Dfile.encoding=UTF-8</argLine>
+					<useSystemClassLoader>false</useSystemClassLoader>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.jacoco</groupId>
+				<artifactId>jacoco-maven-plugin</artifactId>
+				<version>${maven.jacoco.version}</version>
+				<executions>
+					<execution>
+						<goals>
+							<goal>prepare-agent</goal>
+						</goals>
+					</execution>
+					<execution>
+						<id>report</id>
+						<phase>test</phase>
+						<goals>
+							<goal>report</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-surefire-plugin</artifactId>
+					<version>${maven.surefire.version}</version>
+				</plugin>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-jar-plugin</artifactId>
+					<version>${maven.jar.version}</version>
+				</plugin>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-gpg-plugin</artifactId>
+					<version>${maven.gpg.version}</version>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+
+	<profiles>
+		<profile>
+			<build>
+				<plugins>
+					<!-- Source -->
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-source-plugin</artifactId>
+						<version>${maven.source.version}</version>
+						<executions>
+							<execution>
+								<phase>package</phase>
+								<goals>
+									<goal>jar-no-fork</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+					<!-- Javadoc -->
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-javadoc-plugin</artifactId>
+						<version>${maven.javadoc.version}</version>
+						<executions>
+							<execution>
+								<phase>package</phase>
+								<goals>
+									<goal>jar</goal>
+								</goals>
+								<configuration>
+									<locale>en_US</locale>
+									<encoding>UTF-8</encoding>
+									<charset>UTF-8</charset>
+									<doclint>none</doclint>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+					<!-- GPG -->
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-gpg-plugin</artifactId>
+						<version>${maven.gpg.version}</version>
+						<executions>
+							<execution>
+								<phase>verify</phase>
+								<goals>
+									<goal>sign</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+
+		</profile>
+	</profiles>
+
+	<repositories>
+		<repository>
+			<id>integrated</id>
+			<name>releases Repository</name>
+			<url>http://47.93.132.139:8081/nexus/content/repositories/integrated/</url>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</repository>
+	</repositories>
+
+	<pluginRepositories>
+		<pluginRepository>
+			<id>central</id>
+			<url>http://maven.aliyun.com/nexus/content/groups/public</url>
+		</pluginRepository>
+	</pluginRepositories>
+
+	<modules>
+		<module>saas-common</module>
+		<module>saas-gateway</module>
+		<module>saas-account</module>
+		<module>saas-sso</module>
+	</modules>
+
+</project>

+ 79 - 0
saas-account/pom.xml

@@ -0,0 +1,79 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	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.persagy</groupId>
+		<artifactId>saas-platform</artifactId>
+		<version>0.0.1-SNAPSHOT</version>
+	</parent>
+	<artifactId>saas-account-server</artifactId>
+
+	<dependencies>
+		<!-- 依赖集成自定义jar -->
+		<dependency>
+			<groupId>com.persagy</groupId>
+			<artifactId>saas-common</artifactId>
+		</dependency>
+		<!-- 使用集成注册中心、配置中心 -->
+		<dependency>
+			<groupId>com.persagy</groupId>
+			<artifactId>integrated-config-client</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.persagy</groupId>
+			<artifactId>integrated-ribbon-spring-boot-starter</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.persagy</groupId>
+			<artifactId>integrated-swagger2-spring-boot-starter</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.persagy</groupId>
+			<artifactId>integrated-db-spring-boot-starter</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.persagy</groupId>
+			<artifactId>integrated-redis-spring-boot-starter</artifactId>
+		</dependency>
+		
+		<!-- mysql -->
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+		</dependency>
+		
+		<!-- web -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+
+		<!-- rabbitmq -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-amqp</artifactId>
+		</dependency>
+		
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-actuator</artifactId>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<finalName>saas-account</finalName>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<executions>
+					<execution>
+						<goals>
+							<goal>repackage</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+</project>

+ 27 - 0
saas-account/src/main/java/com/persagy/AccountServerApplication.java

@@ -0,0 +1,27 @@
+package com.persagy;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+import com.persagy.common.annotation.EnableIdGenerator;
+import com.persagy.log.annotation.EnableControllerLog;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年2月26日:	下午4:35:08
+ */
+@EnableIdGenerator
+@EnableControllerLog
+@SpringBootApplication
+@EnableFeignClients(basePackages = "com.persagy.person.client")
+public class AccountServerApplication {
+	
+	public static void main(String[] args) {
+		SpringApplication.run(AccountServerApplication.class, args);
+	}
+	
+}

+ 37 - 0
saas-account/src/main/java/com/persagy/person/aop/GlobalExceptionHandler.java

@@ -0,0 +1,37 @@
+package com.persagy.person.aop;
+
+import java.sql.SQLIntegrityConstraintViolationException;
+
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import com.alibaba.excel.exception.ExcelAnalysisException;
+import com.persagy.common.aop.GlobalBussinessExceptionHandler;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @description 
+ * @author zhangqiankun
+ * @since 2020年8月26日:	下午5:17:08
+ */
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler extends GlobalBussinessExceptionHandler {
+	
+	@ExceptionHandler(ExcelAnalysisException.class)
+	public ResponseResult handleExcelAnalysisException(ExcelAnalysisException e) {
+		log.error("文件上传数据解析失败", e);
+		return ResponseResultUtil.errorResult(ResponseCode.B0001.getCode(), e.getMessage());
+	}
+	
+	@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
+	public ResponseResult handleSQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) {
+		log.error("sql语句异常", e);
+		return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), ResponseCode.C0341.getDesc());
+	}
+
+}

+ 51 - 0
saas-account/src/main/java/com/persagy/person/config/ApplicationProperties.java

@@ -0,0 +1,51 @@
+package com.persagy.person.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @version 
+ * @description
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2020年11月25日:	下午4:17:36
+ */
+@Getter
+@Setter
+@Component
+public class ApplicationProperties {
+
+	@Value("${saas.system.default-menu-id}")
+	private String defaultMenuId;
+	
+	@Value("${saas.rabitmq.enable:false}")
+	private boolean raabitmqEnable;
+	
+	@Value("${saas.rabitmq.common-exchange}")
+	private String commonExchange;
+	
+	@Value("${saas.rabitmq.group-route-key}")
+	private String groupRouteKey;
+	
+	@Value("${saas.rabitmq.account-route-key}")
+	private String accountRouteKey;
+	
+	@Value("${saas.secure.aes.key}")
+	private String aesKey;
+	
+	@Value("${saas.secure.aes.iv}")
+	private String aesIv;
+	
+	@Value("${saas.user.token.expire}")
+	private String tokenExpire;
+	
+	@Value("${saas.user.token.salt}")
+	private String tokenSalt;
+	
+	@Value("${saas.user.default.password}")
+	private String defaultPwd;
+	
+}

+ 81 - 0
saas-account/src/main/java/com/persagy/person/config/RabbitMQConfig.java

@@ -0,0 +1,81 @@
+package com.persagy.person.config;
+
+import org.springframework.amqp.core.TopicExchange;
+import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.rabbit.core.RabbitAdmin;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Configurable;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+import com.persagy.person.mq.CommonConfirmCallback;
+
+/**
+ * 采用jackson序列号消息内容
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2020年9月15日:	下午2:09:17
+ */
+@Component
+public class RabbitMQConfig {
+	
+	@Autowired
+    private RabbitAdmin rabbitAdmin;
+	
+	@Autowired
+	private ApplicationProperties properties;
+	
+	@Bean
+	public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
+		RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
+		// 只有设置为 true,spring 才会加载 RabbitAdmin 这个类
+		rabbitAdmin.setAutoStartup(true);
+		return rabbitAdmin;
+	}
+	
+	@Bean
+	public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
+		RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
+		rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
+		return rabbitTemplate;
+	}
+	
+	@Bean
+	public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
+		SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
+		factory.setConnectionFactory(connectionFactory);
+		factory.setMessageConverter(new Jackson2JsonMessageConverter());
+		return factory;
+	}
+	
+    @Bean
+    public TopicExchange commonTopicExchange() {
+    	// 这里设置为true, 实际由回调机制保证消息的可靠性
+        return new TopicExchange(properties.getCommonExchange(), true, false);
+    }
+    
+	@Bean
+	public void createExchange (){
+		rabbitAdmin.declareExchange(commonTopicExchange());
+	}
+	
+}
+
+@Configurable
+class RabbitInitializingBean implements InitializingBean {
+
+	@Autowired
+	private RabbitTemplate rabbitTemplate;
+	
+	@Override
+	public void afterPropertiesSet() throws Exception {
+		this.rabbitTemplate.setConfirmCallback(new CommonConfirmCallback());
+	}
+	
+}

+ 83 - 0
saas-account/src/main/java/com/persagy/person/config/SpringMVCConfig.java

@@ -0,0 +1,83 @@
+package com.persagy.person.config;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpOutputMessage;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.util.StreamUtils;
+
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson.support.config.FastJsonConfig;
+import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
+
+/**
+ * @description 
+ * @author zhangqiankun
+ * @since 2020年8月26日:	下午5:17:08
+ */
+@Configuration
+public class SpringMVCConfig {
+	private static final String ENCODE_UTF_8 = "UTF-8";
+	
+	/**
+	 * HttpMessageConverters - FastJson
+	 * 首字母会改为小写,如有必要,手动在实体类上加上@JSONField 注解
+	 */
+	@Bean
+	public HttpMessageConverters fastJsonHttpMessageConverters() {
+		// 1、定义一个convert转换消息的对象
+		FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverterConfig();
+
+		// 2、添加fastjson的配置信息
+		FastJsonConfig fastJsonConfig = new FastJsonConfig();
+
+		SerializerFeature[] serializerFeatures = new SerializerFeature[] {
+				// 循环引用
+				SerializerFeature.DisableCircularReferenceDetect
+			};
+
+		fastJsonConfig.setSerializerFeatures(serializerFeatures);
+		fastJsonConfig.setCharset(Charset.forName(ENCODE_UTF_8));
+		
+		//3、设置类型
+		List<MediaType> mediaTypes = new ArrayList<MediaType>();
+		mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
+		mediaTypes.add(MediaType.TEXT_PLAIN);
+		mediaTypes.add(MediaType.ALL);
+		fastConverter.setSupportedMediaTypes(mediaTypes);
+        
+        //4、将转换规则应用于转换对象 
+        fastConverter.setFastJsonConfig(fastJsonConfig);
+        fastConverter.setDefaultCharset(Charset.forName(ENCODE_UTF_8));
+        
+        return new HttpMessageConverters(fastConverter);
+	}
+
+}
+
+class FastJsonHttpMessageConverterConfig extends FastJsonHttpMessageConverter{
+	
+	@Override
+	protected void writeInternal(Object obj, HttpOutputMessage outputMessage)
+			throws IOException, HttpMessageNotWritableException {
+		if (obj instanceof String) {
+			//设置 字符串返回的 ContentType 类型
+			HttpHeaders headers = outputMessage.getHeaders();
+			//headers.setContentType(MediaType.TEXT_PLAIN);
+			headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
+			Charset charset = this.getDefaultCharset();
+	        StreamUtils.copy((String) obj, charset, outputMessage.getBody());
+		} else {
+			super.writeInternal(obj, outputMessage);
+		}
+	}
+
+}

+ 301 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasAccountController.java

@@ -0,0 +1,301 @@
+package com.persagy.person.controller;
+
+import java.util.List;
+
+import com.persagy.person.pojo.vo.account.*;
+import com.persagy.security.util.BouncycastleCipher;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.model.BaseGroupModel;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.config.ApplicationProperties;
+import com.persagy.person.manage.SaasAccountHandler;
+import com.persagy.person.pojo.dto.SaasAccount;
+import com.persagy.person.pojo.dto.SaasRole;
+import com.persagy.person.service.ISaasAccountService;
+import com.persagy.person.service.ISaasRoleService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.BooleanUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 账号信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+
+@Api(tags = "账号信息")
+@RestController
+@RequestMapping(value = "/account", method = RequestMethod.POST)
+public class SaasAccountController {
+	
+	@Autowired
+	private ApplicationProperties properties;
+	
+    @Autowired
+    private ISaasRoleService saasRoleService;
+    
+    @Autowired
+    private BouncycastleCipher bouncycastleCipher;
+    
+	@Autowired
+	private SaasAccountHandler saasAccountHandler;
+	
+    @Autowired
+    private ISaasAccountService saasAccountService;
+
+    /**
+     * 账号信息查询
+     */
+    @ApiOperation(value = "账号信息查询")
+    @RequestMapping(value = "querySaasAccountList")
+    public ResponseResult querySaasAccountList(@RequestBody @Validated SaasAccountQueryVO queryVO) {
+    	SaasAccount saasAccount = new SaasAccount();
+		BeanUtils.copyProperties(queryVO, saasAccount);
+		saasAccount.setId(queryVO.getAccountId());
+		
+		LambdaQueryWrapper<SaasAccount> queryWrapper = this.saasAccountService.getQueryWrapper(saasAccount);
+		if (BooleanUtil.isTrue(queryVO.getGroupIsNull())) {
+			queryWrapper.apply("(GROUP_CODE IS NULL OR TRIM(GROUP_CODE) = '')");
+		}
+		queryWrapper.orderByDesc(SaasAccount::getUpdateTime);		//更新时间降序
+    	List<SaasAccount> list = this.saasAccountService.list(queryWrapper);
+    	if (CollectionUtil.isEmpty(list)) {
+			return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+    
+    /**
+     * 账号分页信息查询-普通列表
+     */
+    @ApiOperation(value = "账号分页信息查询")
+    @RequestMapping(value = "queryAccountPageList")
+    public ResponseResult queryAccountPageList(@RequestBody @Validated SaasAccountPageVO pageVO) {
+    	SaasAccount saasAccount = new SaasAccount();
+		BeanUtils.copyProperties(pageVO, saasAccount);
+		saasAccount.setId(pageVO.getAccountId());
+		
+    	Page<SaasAccount> pageList = null;
+    	if (BooleanUtil.isTrue(pageVO.getShowGroup())) {
+    		pageList = this.saasAccountService.queryAccountPageList(saasAccount, pageVO.getPage(), pageVO.getSize());
+		} else {
+			Page<SaasAccount> page = new Page<SaasAccount>(pageVO.getPage(), pageVO.getSize());
+			LambdaQueryWrapper<SaasAccount> queryWrapper = this.saasAccountService.getQueryWrapper(saasAccount);
+			queryWrapper.orderByDesc(SaasAccount::getUpdateTime);		//更新时间降序
+	    	pageList = this.saasAccountService.page(page, queryWrapper);
+		}
+    	if (pageList == null || CollectionUtil.isEmpty(pageList.getRecords())) {
+    		return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+    	// 额外信息补充
+    	List<SaasAccount> records = pageList.getRecords();
+    	if (BooleanUtil.isTrue(pageVO.getShowRoles())) {
+    		// 获取角色集合
+    		for (SaasAccount account : records) {
+    			List<SaasRole> roleList = this.saasRoleService.querySaasRoleList(account.getId());
+    			account.setRoles(roleList);
+    		}
+		}
+    	return ResponseResultUtil.successResult(records, pageList.getTotal());
+    }
+    
+    /**
+     * 新增,登录用户名,全局唯一
+     */
+	@ApiOperation(value = "保存")
+	@RequestMapping(value = "createSaasAccount")
+    public ResponseResult createSaasAccount(@RequestBody @Validated SaasAccountCreateVO createVO) {
+		if (createVO.getValid() == null) {
+			createVO.setValid(SaasCommonConstant.STATUS_1);
+		}
+		if (SaasCommonConstant.STR_STATUS_0.equals(createVO.getValidLast())) {
+			if (!(createVO.getValidStartTime() != null && createVO.getValidEndTime() != null)) {
+				return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "当validLast为0时,账号有效期时间字段不可为空");
+			}
+		}
+		if (createVO.isVerify() && SaasCommonConstant.STR_STATUS_1.equals(createVO.getAccountBelong()) && StringUtil.isBlank(createVO.getGroupCode())) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "业务系统账号,请先关联集团");
+		}
+		boolean exists = this.saasAccountService.validAccountName(createVO.getUsername(), createVO.getMail(), createVO.getPhoneNum(), null, false);
+		if (!exists) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "账号用户名、邮箱、手机号,存在重复");
+		}
+		SaasAccount saasAccount = new SaasAccount();
+		BeanUtils.copyProperties(createVO, saasAccount);
+		saasAccount.setUpdateUser(createVO.getAccountId());
+		saasAccount.setId(null);
+		if (StringUtil.isBlank(createVO.getPassword())) {
+			saasAccount.setPassword(this.properties.getDefaultPwd());
+		}
+		exists = this.saasAccountHandler.createSaasAccount(saasAccount, createVO.getCasType(), createVO.getRoles());
+		return exists ? ResponseResultUtil.successResult("保存成功", saasAccount.getId()) : ResponseResultUtil.errorResult("保存失败");
+    }
+    
+    /**
+     * 更新
+     */
+	@ApiOperation(value = "更新")
+	@RequestMapping(value = "updateSaasAccount")
+    public ResponseResult updateSaasAccount(@RequestBody @Validated SaasAccountCreateVO createVO) {
+		createVO.setPassword(null);		//目前不允许更新时,更新密码
+		if (StringUtil.isBlank(createVO.getAccountId())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "主键ID,不可为空");
+		}
+		if (createVO.getValid() == null) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "账号状态不可为空");
+		}
+		if (SaasCommonConstant.STR_STATUS_0.equals(createVO.getValidLast())) {
+			if (!(createVO.getValidStartTime() != null && createVO.getValidEndTime() != null)) {
+				return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "当validLast为0时,账号有效期时间字段不可为空");
+			}
+		}
+		if (createVO.isVerify() && SaasCommonConstant.STR_STATUS_1.equals(createVO.getAccountBelong()) && StringUtil.isBlank(createVO.getGroupCode())) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "业务系统账号,集团编码不可为空");
+		}
+		boolean exists = this.saasAccountService.validAccountName(createVO.getUsername(), createVO.getMail(), createVO.getPhoneNum(), createVO.getAccountId(), true);
+		if (!exists) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "账号用户名、邮箱、手机号,存在重复");
+		}
+		SaasAccount saasAccount = new SaasAccount();
+		BeanUtils.copyProperties(createVO, saasAccount);
+		saasAccount.setId(createVO.getAccountId());
+		saasAccount.setUpdateUser(createVO.getAccountId());
+		exists = this.saasAccountHandler.updateSaasAccount(saasAccount, createVO.getCasType(), createVO.getRoles());
+		return exists ? ResponseResultUtil.successResult("更新成功") : ResponseResultUtil.errorResult("更新失败");
+    }
+
+	/**
+     * 业务超管账号关联集团
+     */
+    @ApiOperation(value = "集团关联业务超管账号")
+    @RequestMapping(value = "addSaasAccountGroup")
+    public ResponseResult addSaasAccountGroup(@RequestBody @Validated BaseGroupModel model) {
+    	boolean result = this.saasAccountHandler.addSaasAccountGroup(model);
+        return result ? ResponseResultUtil.successResult("关联成功") : ResponseResultUtil.errorResult("关联失败");
+    }
+    
+    /**
+     * 逻辑删除
+     */
+    @ApiOperation(value = "禁用")
+    @RequestMapping(value = "deleteSaasAccount")
+    public ResponseResult deleteSaasAccount(@RequestBody @Validated BaseGroupModel deleteModel) {
+    	// 验证数据是否存在
+    	SaasAccount account = this.saasAccountService.getOne(deleteModel.getAccountId(), deleteModel.getGroupCode(), null);
+    	if (account == null) {
+    		return ResponseResultUtil.errorResult(ResponseCode.C0320.getCode(), ResponseCode.C0320.getDesc());
+		}
+    	// 逻辑删除
+    	boolean result = this.saasAccountHandler.deleteSaasAccount(deleteModel);
+    	if (result) {
+			// 移除token
+        	this.bouncycastleCipher.remove(deleteModel.getAccountId());
+		}
+        return result ? ResponseResultUtil.successResult("禁用成功") : ResponseResultUtil.errorResult("禁用失败");
+    }
+    
+    /**
+     * 启用
+     */
+    @ApiOperation(value = "启用")
+    @RequestMapping(value = "enableSaasAccount")
+    public ResponseResult enableSaasAccount(@RequestBody @Validated BaseGroupModel model) {
+    	LambdaUpdateWrapper<SaasAccount> updateWrapper = new SaasAccount.Builder().createUpdateWrapper()
+				.idEq(model.getAccountId()).groupCodeEq(model.getGroupCode())
+				.validEq(SaasCommonConstant.STATUS_0).builderUpdateWrapper();
+    	updateWrapper.set(SaasAccount::getUpdateUser, model.getAccountId());
+    	updateWrapper.set(SaasAccount::getValid, SaasCommonConstant.STATUS_1);
+    	boolean result = this.saasAccountService.update(updateWrapper);
+        return result ? ResponseResultUtil.successResult("启用成功") : ResponseResultUtil.errorResult("启用失败");
+    }
+    
+    
+    /**
+     * 修改密码
+     */
+    @ApiOperation(value = "修改密码")
+    @RequestMapping(value = "updateAccountPwd")
+    public ResponseResult updateAccountPwd(@RequestBody @Validated SaasAccountGroupVO model) {
+    	if (StringUtil.isBlank(model.getOldPassword())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "账号旧密码,不可为空");
+		}
+    	if (StringUtil.isBlank(model.getNewPassword())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "账号新密码,不可为空");
+		}
+    	// 验证数据是否存在
+    	SaasAccount account = this.saasAccountService.getOne(model.getAccountId(), model.getGroupCode(), null);
+    	if (account == null) {
+    		return ResponseResultUtil.errorResult(ResponseCode.C0320.getCode(), ResponseCode.C0320.getDesc());
+		}
+    	// 修改密码
+    	LambdaUpdateWrapper<SaasAccount> updateWrapper = new SaasAccount.Builder().createUpdateWrapper().idEq(model.getAccountId())
+				.groupCodeEq(model.getGroupCode()).validEq(SaasCommonConstant.STATUS_1).passwordEq(model.getOldPassword()).builderUpdateWrapper();
+    	updateWrapper.set(SaasAccount::getUpdateUser, model.getAccountId());
+    	updateWrapper.set(SaasAccount::getPassword, model.getNewPassword());
+    	boolean result = this.saasAccountService.update(updateWrapper);
+        return result ? ResponseResultUtil.successResult("密码修改成功") : ResponseResultUtil.errorResult("密码修改失败");
+    }
+    
+    
+    /**
+     * 重置密码
+     */
+    @ApiOperation(value = "重置密码")
+    @RequestMapping(value = "resetAccountPwd")
+    public ResponseResult resetAccountPwd(@RequestBody @Validated SaasAccountGroupVO model) {
+    	// 验证数据是否存在
+    	SaasAccount account = this.saasAccountService.getById(model.getAccountId());
+    	if (account == null) {
+    		return ResponseResultUtil.errorResult(ResponseCode.C0320.getCode(), ResponseCode.C0320.getDesc());
+		}
+    	// 重置密码
+    	LambdaUpdateWrapper<SaasAccount> updateWrapper = new SaasAccount.Builder().createUpdateWrapper().idEq(model.getAccountId())
+				.groupCodeEq(model.getGroupCode()).validEq(SaasCommonConstant.STATUS_1).builderUpdateWrapper();
+    	updateWrapper.set(SaasAccount::getUpdateUser, model.getAccountId());
+    	updateWrapper.set(SaasAccount::getPassword, this.properties.getDefaultPwd());
+    	boolean result = this.saasAccountService.update(updateWrapper);
+        return result ? ResponseResultUtil.successResult("密码重置成功") : ResponseResultUtil.errorResult("密码重置失败");
+    }
+
+
+    /**
+     * 根据账号名称获取账号信息
+     */
+    @ApiOperation(value = "根据账号名称获取账号信息")
+    @RequestMapping(value = "querySaasAccountByUsername")
+    public ResponseResult querySaasAccountByUsername(@RequestBody @Validated SaasAccountQueryByNameVO queryVO) {
+        SaasAccount saasAccount = new SaasAccount();
+        BeanUtils.copyProperties(queryVO, saasAccount);
+        LambdaQueryWrapper<SaasAccount> queryWrapper = this.saasAccountService.getQueryWrapperByUsername(saasAccount);
+        queryWrapper.orderByDesc(SaasAccount::getUpdateTime);		//更新时间降序
+        List<SaasAccount> list = this.saasAccountService.list(queryWrapper);
+        if (CollectionUtil.isEmpty(list)) {
+            return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+        }
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+
+
+
+    
+}

+ 198 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasAccountProjectController.java

@@ -0,0 +1,198 @@
+package com.persagy.person.controller;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.manage.SaasAuthHandler;
+import com.persagy.person.pojo.dto.SaasAccount;
+import com.persagy.person.pojo.dto.SaasAccountProject;
+import com.persagy.person.pojo.dto.SaasGroup;
+import com.persagy.person.pojo.dto.SaasProject;
+import com.persagy.person.pojo.vo.auth.SaasAccountProjectBatchVO;
+import com.persagy.person.pojo.vo.auth.SaasAccountProjectCreateVO;
+import com.persagy.person.pojo.vo.auth.SaasAccountProjectPageVO;
+import com.persagy.person.pojo.vo.auth.SaasAccountProjectQueryVO;
+import com.persagy.person.service.ISaasAccountProjectService;
+import com.persagy.person.service.ISaasAccountService;
+import com.persagy.person.service.ISaasGroupService;
+import com.persagy.person.service.ISaasProjectService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 账号-集团项目关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+
+@Api(tags = "账号-集团区域项目关联信息")
+@RestController
+@RequestMapping(value = "/accountProject", method = RequestMethod.POST)
+public class SaasAccountProjectController {
+	
+	@Autowired
+	private SaasAuthHandler saasAuthHandler;
+	
+    @Autowired
+    private ISaasGroupService saasGroupService;
+
+    @Autowired
+    private ISaasAccountService saasAccountService;
+    
+    @Autowired
+    private ISaasProjectService saasProjectService;
+    
+    @Autowired
+    private ISaasAccountProjectService saasAccountProjectService;
+    
+    /**
+     * 账号-集团项目普通列表查询
+     */
+    @ApiOperation(value = "账号-集团区域项目普通列表查询")
+    @RequestMapping(value = "querySaasAccountProjectList")
+    public ResponseResult querySaasAccountProjectList(@RequestBody @Validated SaasAccountProjectQueryVO queryVO) {
+    	LambdaQueryWrapper<SaasAccountProject> queryWrapper = new SaasAccountProject.Builder().createQueryWrapper()
+    			.groupCodeEq(queryVO.getGroupCode()).accountIdEq(queryVO.getAccountId()).areaIdEq(queryVO.getAreaId())
+    			.projectIdEq(queryVO.getProjectId()).builderQueryWrapper();
+    	List<SaasAccountProject> list = this.saasAccountProjectService.list(queryWrapper);
+    	if (CollectionUtil.isEmpty(list)) {
+			return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+    
+    /**
+     * 账号-集团项目数量统计列表分页查询
+     */
+    @ApiOperation(value = "账号-集团区域项目数量统计列表分页查询")
+    @RequestMapping(value = "querAccountProjectTotal")
+    public ResponseResult querAccountProjectTotal(@RequestBody @Validated SaasAccountProjectPageVO pageVO) {
+    	SaasAccount saasAccount = new SaasAccount();
+    	BeanUtils.copyProperties(pageVO, saasAccount);
+    	saasAccount.setId(pageVO.getAccountId());
+    	saasAccount.setValid(SaasCommonConstant.STATUS_1);
+    	
+    	// 先判断此账号的权限
+    	Map<String, String> authMap = this.saasAuthHandler.validGroupProjectAuth(pageVO.getAccountId(), pageVO.getGroupCode());
+    	if (StringUtil.isNotBlank(authMap.get(SaasCommonConstant.GROUP_CODE))) {
+    		pageVO.setGroupCode(authMap.get(SaasCommonConstant.GROUP_CODE));
+		}
+		String accountType = authMap.get(SaasCommonConstant.ACCOUNT_TYPE);
+		if (SaasCommonConstant.STR_STATUS_0.equals(accountType)) {
+			saasAccount.setId(null);
+		}
+    	Page<SaasAccount> pageList = this.saasAccountService.queryAccountPageList(saasAccount, pageVO.getPage(), pageVO.getSize());
+    	if (pageList == null || CollectionUtil.isEmpty(pageList.getRecords())) {
+    		return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+    	// 补充集团和项目信息
+    	List<SaasAccount> records = pageList.getRecords();
+    	SaasGroup saasGroup = new SaasGroup();
+		saasGroup.setValid(SaasCommonConstant.STATUS_1);
+    	for (SaasAccount account : records) {
+    		account.setPassword(null);		// 剔除密码
+    		// 超管,就是所有的集团和项目
+    		if (SaasCommonConstant.STR_STATUS_0.equals(account.getAccountType())) {
+				LambdaQueryWrapper<SaasGroup> queryWrapper = new SaasGroup.Builder().createQueryWrapper().validEq(SaasCommonConstant.STATUS_1).builderQueryWrapper();
+				queryWrapper.select(SaasGroup::getGroupCode, SaasGroup::getGroupName);
+				List<SaasGroup> groups = this.saasGroupService.list(queryWrapper);
+				account.setGroups(groups);
+				
+				LambdaQueryWrapper<SaasProject> wrapper = new SaasProject.Builder().createQueryWrapper().validEq(SaasCommonConstant.STATUS_1).builderQueryWrapper();
+				int count = this.saasProjectService.count(wrapper);
+				account.setProjectNum(count);
+			} else if (SaasCommonConstant.STR_STATUS_1.equals(account.getAccountType())) {
+				// 业务超管
+				LambdaQueryWrapper<SaasGroup> queryWrapper = new SaasGroup.Builder().createQueryWrapper()
+						.groupCodeEq(account.getGroupCode()).validEq(SaasCommonConstant.STATUS_1).builderQueryWrapper();
+				queryWrapper.select(SaasGroup::getGroupCode, SaasGroup::getGroupName);
+				List<SaasGroup> groups = this.saasGroupService.list(queryWrapper);
+				account.setGroups(groups);
+				
+				LambdaQueryWrapper<SaasProject> wrapper = new SaasProject.Builder().createQueryWrapper()
+						.groupCodeEq(account.getGroupCode()).validEq(SaasCommonConstant.STATUS_1).builderQueryWrapper();
+				int count = this.saasProjectService.count(wrapper);
+				account.setProjectNum(count);
+			} else {
+				// 普通账号,表关联查询
+				List<SaasGroup> groups = this.saasGroupService.queryAllowGroupInfo(saasGroup, account.getId());
+				account.setGroups(groups);
+				
+				int projectNum = this.saasProjectService.countAllowProjectNum(null, account.getId(), null);
+				account.setProjectNum(projectNum);
+			}
+		}
+        return ResponseResultUtil.successResult(records, pageList.getTotal());
+    }
+    
+    /**
+     * 账号-集团项目关联信息新增
+     * 账号可见域,0-所有集团项目,1-单集团所有项目(此时,集团编码需存在),2-其他
+     */
+	@ApiOperation(value = "新增账号-集团区域项目关联信息")
+	@RequestMapping(value = "createSaasAccountProject")
+    public ResponseResult createSaasAccountProject(@RequestBody @Validated SaasAccountProjectCreateVO createVO) {
+		// 验证集团信息是否存在
+		SaasGroup group = this.saasGroupService.getOne(createVO.getGroupCode());
+		if (group == null) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "集团信息不存在");
+		}
+		// 验证项目信息是否存在
+		if (StringUtil.isNotBlank(createVO.getProjectId())) {
+			SaasProject saasProject = this.saasProjectService.getOne(createVO.getGroupCode(), createVO.getProjectId());
+			if (saasProject == null) {
+				return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "项目信息不存在");
+			}
+		}
+		SaasAccountProject saasAccountProject = new SaasAccountProject();
+		BeanUtils.copyProperties(createVO, saasAccountProject);
+        boolean result = this.saasAccountProjectService.save(saasAccountProject);
+        return result ? ResponseResultUtil.successResult("保存成功") : ResponseResultUtil.errorResult("保存失败");
+    }
+    
+	
+	/**
+     * 账号-集团项目关联信息更新
+     */
+	@ApiOperation(value = "删除新增账号-集团区域项目关联信息")
+	@RequestMapping(value = "resetSaasAccountProject")
+    public ResponseResult resetSaasAccountProject(@RequestBody @Validated SaasAccountProjectBatchVO batchVO) {
+		boolean result = this.saasAccountProjectService.resetSaasAccountProject(batchVO.getAccountId(), batchVO.getAuths());
+        return result ? ResponseResultUtil.successResult("重置成功") : ResponseResultUtil.errorResult("重置失败");
+    }
+	
+    /**
+     * 账号-集团项目关联信息删除
+     */
+	@ApiOperation(value = "删除账号-集团区域项目关联信息")
+	@RequestMapping(value = "deleteSaasAccountProject")
+    public ResponseResult deleteSaasAccountProject(@RequestBody @Validated SaasAccountProjectQueryVO queryVO) {
+		LambdaQueryWrapper<SaasAccountProject> updateWrapper = new SaasAccountProject.Builder().createQueryWrapper()
+				.accountIdEq(queryVO.getAccountId()).groupCodeEq(queryVO.getGroupCode()).areaIdEq(queryVO.getAreaId())
+				.projectIdEq(queryVO.getProjectId()).builderQueryWrapper();
+		boolean result = this.saasAccountProjectService.remove(updateWrapper);
+        return result ? ResponseResultUtil.successResult("删除成功") : ResponseResultUtil.errorResult("删除失败");
+    }
+
+}

+ 98 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasAccountRoleController.java

@@ -0,0 +1,98 @@
+package com.persagy.person.controller;
+
+import java.util.List;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.google.common.collect.Lists;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.pojo.dto.SaasAccountRole;
+import com.persagy.person.pojo.vo.auth.SaasAccountRoleBatchVO;
+import com.persagy.person.pojo.vo.auth.SaasAccountRoleCreateVO;
+import com.persagy.person.pojo.vo.auth.SaasAccountRoleQueryVO;
+import com.persagy.person.service.ISaasAccountRoleService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 账号-角色关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+
+@Api(tags = "账号-角色关联信息")
+@RestController
+@RequestMapping(value = "/accountRole", method = RequestMethod.POST)
+public class SaasAccountRoleController {
+
+	@Autowired
+    private ISaasAccountRoleService saasAccountRoleService;
+    
+    /**
+     * 查询账号-角色关联信息
+     */
+    @ApiOperation(value = "查询账号-角色关联信息")
+    @RequestMapping(value = "querySaasRoleMenuList")
+    public ResponseResult querySaasRoleMenuList(@RequestBody @Validated SaasAccountRoleQueryVO queryVO) {
+    	if (StringUtil.isBlank(queryVO.getAccountId()) && CollectionUtil.isEmpty(queryVO.getAccountIds())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0402.getDesc(), "账号ID与账号ID集合参数必须存在其一");
+		}
+    	LambdaQueryWrapper<SaasAccountRole> queryWrapper = new SaasAccountRole.Builder().createQueryWrapper().accountIdEq(queryVO.getAccountId())
+				.accountIdIn(queryVO.getAccountIds()).groupCodeEq(queryVO.getGroupCode()).roleIdEq(queryVO.getRoleId()).builderQueryWrapper();
+    	List<SaasAccountRole> list = this.saasAccountRoleService.list(queryWrapper);
+    	if (CollectionUtil.isEmpty(list)) {
+			return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+    
+    /**
+     * 新增
+     */
+	@ApiOperation(value = "新增账号-角色关联信息")
+	@RequestMapping(value = "createSaasAccountRole")
+    public ResponseResult createSaasAccountRole(@RequestBody @Validated SaasAccountRoleCreateVO createVO) {
+		SaasAccountRole saasAccountRole = new SaasAccountRole();
+		BeanUtils.copyProperties(createVO, saasAccountRole);
+        boolean result = this.saasAccountRoleService.save(saasAccountRole);
+        return result ? ResponseResultUtil.successResult("保存成功") : ResponseResultUtil.errorResult("保存失败");
+    }
+    
+    /**
+     * 删除新增
+     */
+	@ApiOperation(value = "删除新增账号-角色关联信息")
+	@RequestMapping(value = "resetSaasAccountRole")
+    public ResponseResult resetSaasAccountRole(@RequestBody @Validated SaasAccountRoleBatchVO batchVO) {
+		boolean result = this.saasAccountRoleService.resetSaasAccountRole(batchVO.getGroupCode(), batchVO.getAccountId(), batchVO.getCasType(), batchVO.getRoles());
+        return result ? ResponseResultUtil.successResult("重置成功") : ResponseResultUtil.errorResult("重置失败");
+    }
+	
+    /**
+     * 物理删除
+     */
+	@ApiOperation(value = "删除账号-角色关联信息")
+	@RequestMapping(value = "deleteSaasAccountRole")
+    public ResponseResult updateSaasAccountRole(@RequestBody @Validated SaasAccountRoleQueryVO deleteVO) {
+		LambdaQueryWrapper<SaasAccountRole> queryWrapper = new SaasAccountRole.Builder().createQueryWrapper().accountIdEq(deleteVO.getAccountId())
+				.groupCodeEq(deleteVO.getGroupCode()).roleIdEq(deleteVO.getRoleId()).casTypeEq(deleteVO.getCasType()).builderQueryWrapper();
+        boolean result = this.saasAccountRoleService.remove(queryWrapper);
+        return result ? ResponseResultUtil.successResult("删除成功") : ResponseResultUtil.errorResult("删除失败");
+    }
+
+}

+ 225 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasAreaController.java

@@ -0,0 +1,225 @@
+package com.persagy.person.controller;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.manage.SaasAreaProjectHandler;
+import com.persagy.person.manage.SaasAuthHandler;
+import com.persagy.person.pojo.dto.SaasAccount;
+import com.persagy.person.pojo.dto.SaasArea;
+import com.persagy.person.pojo.dto.SaasProject;
+import com.persagy.person.pojo.vo.BaseGroupVO;
+import com.persagy.person.pojo.vo.area.SaasAreaCreateVO;
+import com.persagy.person.pojo.vo.area.SaasAreaDeleteVO;
+import com.persagy.person.pojo.vo.area.SaasAreaQueryVO;
+import com.persagy.person.service.ISaasAccountService;
+import com.persagy.person.service.ISaasAreaService;
+import com.persagy.person.service.ISaasProjectService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 区域信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+
+@Api(tags = "区域信息")
+@RestController
+@RequestMapping(value = "/area", method = RequestMethod.POST)
+public class SaasAreaController {
+	
+	@Autowired
+	private SaasAuthHandler saasAuthHandler;
+	
+    @Autowired
+    private ISaasAreaService saasAreaService;
+    
+    @Autowired
+    private ISaasProjectService saasProjectService;
+    
+    @Autowired
+    private ISaasAccountService saasAccountService;
+    
+    @Autowired
+    private SaasAreaProjectHandler saasAreaProjectHandler;
+    
+    /**
+     * 查询区域树
+     */
+    @ApiOperation(value = "查询区域树")
+    @RequestMapping(value = "querySaasAreaTree")
+    public ResponseResult querySaasAreaTree(@RequestBody @Validated BaseGroupVO model) {
+    	List<SaasArea> topList = this.saasAreaProjectHandler.getTopAreaList(model.getGroupCode());
+    	this.saasAreaProjectHandler.querySaasAreaTree(topList, false);
+    	return ResponseResultUtil.successResult(topList);
+    }
+    
+    /**
+     * 查询区域权限树,做权限判断
+     */
+    @ApiOperation(value = "查询区域权限树")
+    @RequestMapping(value = "queryAllowAreaTree")
+    public ResponseResult queryAllowAreaTree(@RequestBody @Validated BaseGroupVO groupVO) {
+    	List<SaasArea> areaList = this.saasAuthHandler.getAllowAreaList(groupVO.getAccountId(), groupVO.getGroupCode());
+    	return ResponseResultUtil.successResult(areaList);
+    }
+    
+    /**
+     * 区域平铺列表查询
+     */
+    @ApiOperation(value = "区域平铺列表查询")
+    @RequestMapping(value = "querySaasAreaList")
+    public ResponseResult querySaasAreaList(@RequestBody @Validated SaasAreaQueryVO queryVO) {
+    	boolean isAllProjects = true;
+    	// 如果需要统计项目
+    	if (queryVO.isTotal()) {
+    		// 账号数据可见性的权限鉴定
+    		Map<String, String> authMap = this.saasAuthHandler.validGroupProjectAuth(queryVO.getAccountId(), queryVO.getGroupCode());
+    		if (StringUtil.isNotBlank(authMap.get(SaasCommonConstant.GROUP_CODE))) {
+    			queryVO.setGroupCode(authMap.get(SaasCommonConstant.GROUP_CODE));
+    		}
+        	// 添加数据访问控制,账号可见域,0-所有集团项目,1-单集团所有项目(此时,集团编码需存在),2-其他
+    		String accountType = authMap.get(SaasCommonConstant.ACCOUNT_TYPE);
+    		if (SaasCommonConstant.STR_STATUS_2.equals(accountType)) {
+    			isAllProjects = false;
+    		}
+    	}
+    	// 区域树查询
+    	List<SaasArea> list = this.saasAreaProjectHandler.querySaasAreaList(queryVO, isAllProjects);
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+
+    /**
+     * 底层区域平铺列表查询(权限过滤)
+     */
+    @ApiOperation(value = "底层区域平铺列表查询(权限过滤)")
+    @RequestMapping(value = "queryAllowSaasAreaList")
+    public ResponseResult queryAllowSaasAreaList(@RequestBody @Validated SaasAreaQueryVO queryVO) {
+    	boolean isAdmin = false;
+    	// 账号数据可见性的权限鉴定
+		Map<String, String> authMap = this.saasAuthHandler.validGroupProjectAuth(queryVO.getAccountId(), queryVO.getGroupCode());
+		if (StringUtil.isNotBlank(authMap.get(SaasCommonConstant.GROUP_CODE))) {
+			queryVO.setGroupCode(authMap.get(SaasCommonConstant.GROUP_CODE));
+		}
+    	// 添加数据访问控制,账号可见域,0-所有集团项目,1-单集团所有项目(此时,集团编码需存在),2-其他
+		String accountType = authMap.get(SaasCommonConstant.ACCOUNT_TYPE);
+		List<SaasArea> areas = null;
+		if (SaasCommonConstant.STR_STATUS_2.equals(accountType)) {
+			// 其他类型时,需要根据权限表数据,去匹配区域树
+			SaasArea saasArea = new SaasArea();
+			BeanUtils.copyProperties(queryVO, saasArea);
+			areas = this.saasAreaService.queryAllowSaasAreaList(queryVO.getAccountId(), saasArea);
+		} else {
+			LambdaQueryWrapper<SaasArea> queryWrapper = new SaasArea.Builder().createQueryWrapper().idEq(queryVO.getId())
+	    			.groupCodeEq(queryVO.getGroupCode()).areaCodeEq(queryVO.getAreaCode()).areaNameLike(queryVO.getAreaName())
+	    			.areaTypeEq(queryVO.getAreaType()).updateUserEq(queryVO.getUpdateUser())
+	    			.parentIdEq(queryVO.getParentId()).builderQueryWrapper();
+			areas = this.saasAreaService.list(queryWrapper);
+			isAdmin = true;
+		}
+		if (CollectionUtil.isEmpty(areas)) {
+			return ResponseResultUtil.successResult(Lists.newArrayList(), 0L); 
+		}
+		if (queryVO.isTotal()) {
+			this.saasAreaProjectHandler.totalAreaProjectNum(areas, queryVO.getAccountId(), isAdmin);
+		}
+        return ResponseResultUtil.successResult(areas, (long)areas.size());
+    }
+    
+    /**
+     * 新增,区域编码与区域名称集团下唯一
+     */
+	@ApiOperation(value = "保存")
+	@RequestMapping(value = "createSaasArea")
+    public ResponseResult createSaasArea(@RequestBody @Validated SaasAreaCreateVO createVO) {
+		// 验证账号信息是否存在
+		SaasAccount saasAccount = this.saasAccountService.getOne(createVO.getAccountId(), null, null);
+		if (saasAccount == null) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "账号信息,不存在");
+		}
+		// 验证区域编码与区域名称的唯一性
+		boolean exist = this.saasAreaService.validAreaCodeAndName(createVO.getGroupCode(), createVO.getAreaCode(), createVO.getAreaName(), null);
+		if (!exist) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "区域名称已存在,请检查");
+		}
+		SaasArea saasArea = new SaasArea();
+		BeanUtils.copyProperties(createVO, saasArea);
+		saasArea.setId(null);
+		saasArea.setUpdateUser(createVO.getAccountId());
+		exist = this.saasAreaProjectHandler.createSaasArea(saasArea, saasAccount.getId(), saasAccount.getAccountType());
+        return exist ? ResponseResultUtil.successResult("保存成功", saasArea.getId()) : ResponseResultUtil.errorResult("保存失败");
+    }
+    
+    /**
+     * 更新,区域编码与区域名称集团下唯一
+     */
+	@ApiOperation(value = "更新")
+	@RequestMapping(value = "updateSaasArea")
+    public ResponseResult updateSaasArea(@RequestBody @Validated SaasAreaCreateVO createVO) {
+		if (StringUtil.isBlank(createVO.getId())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "区域ID不可为空");
+		}
+		//验证区域编码与区域名称的唯一性
+		boolean exist = this.saasAreaService.validAreaCodeAndName(createVO.getGroupCode(), createVO.getAreaCode(), createVO.getAreaName(), createVO.getId());
+		if (!exist) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "区域名称已存在,请检查");
+		}
+		SaasArea saasArea = new SaasArea();
+		BeanUtils.copyProperties(createVO, saasArea);
+		saasArea.setUpdateUser(createVO.getAccountId());
+        boolean result = this.saasAreaService.updateById(saasArea);
+        return result ? ResponseResultUtil.successResult("更新成功") : ResponseResultUtil.errorResult("更新失败");
+    }
+
+    /**
+     * 物理删除
+     */
+    @ApiOperation(value = "删除")
+    @RequestMapping(value = "deleteSaasArea")
+    public ResponseResult deleteSaasArea(@RequestBody @Validated SaasAreaDeleteVO deleteVO) {
+    	// 验证账号信息是否存在
+		SaasAccount saasAccount = this.saasAccountService.getOne(deleteVO.getAccountId(), null, null);
+		if (saasAccount == null) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "账号信息,不存在");
+		}
+    	// 验证区域是否存在
+    	SaasArea saasArea = this.saasAreaService.getById(deleteVO.getId());
+    	if (saasArea == null) {
+    		return ResponseResultUtil.errorResult(ResponseCode.C0320.getCode(), "区域信息不存在");
+		}
+    	// 如果是底层区域,判断,旗下是否存在项目信息,存在不允许删除
+    	if (SaasCommonConstant.STR_STATUS_1.equals(saasArea.getAreaType())) {
+    		LambdaQueryWrapper<SaasProject> queryWrapper = new SaasProject.Builder().createQueryWrapper()
+    				.groupCodeEq(deleteVO.getGroupCode()).areaIdEq(deleteVO.getId())
+    				.last("limit 0, 1").builderQueryWrapper();
+			SaasProject project = this.saasProjectService.getOne(queryWrapper);
+			if (project != null) {
+				return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "此区域下存在项目ID,不允许删除");
+			}
+		}
+    	boolean result = this.saasAreaProjectHandler.deleteSaasArea(deleteVO.getGroupCode(), saasArea.getId(), saasAccount.getAccountType());
+        return result ? ResponseResultUtil.successResult("删除成功") : ResponseResultUtil.errorResult("删除失败");
+    }
+    
+}

+ 156 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasFunctionController.java

@@ -0,0 +1,156 @@
+package com.persagy.person.controller;
+
+import java.util.List;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.google.common.collect.Lists;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.manage.SaasRoleMenuHandler;
+import com.persagy.person.pojo.dto.SaasFunction;
+import com.persagy.person.pojo.dto.SaasMenu;
+import com.persagy.person.pojo.dto.SaasRole;
+import com.persagy.person.pojo.vo.function.SaasFunctionCreateVO;
+import com.persagy.person.pojo.vo.function.SaasFunctionDeleteVO;
+import com.persagy.person.pojo.vo.function.SaasFunctionQueryVO;
+import com.persagy.person.service.ISaasFunctionService;
+import com.persagy.person.service.ISaasMenuService;
+import com.persagy.person.service.ISaasRoleService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 功能信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+
+@Api(tags = "功能信息")
+@RestController
+@RequestMapping(value = "/function", method = RequestMethod.POST)
+public class SaasFunctionController {
+	
+    @Autowired
+    private ISaasMenuService saasMenuService;
+    
+    @Autowired
+    private ISaasRoleService saasRoleService;
+    
+    @Autowired
+    private ISaasFunctionService saasFunctionService;
+    
+    @Autowired
+    private SaasRoleMenuHandler saasRoleMenuHandler;
+    
+    /**
+     * 功能点列表查询
+     */
+    @ApiOperation(value = "功能点列表查询")
+    @RequestMapping(value = "querySaasFunctionList")
+    public ResponseResult querySaasFunctionList(@RequestBody @Validated SaasFunctionQueryVO queryVO) {
+    	LambdaQueryWrapper<SaasFunction> queryWrapper = new SaasFunction.Builder().createQueryWrapper()
+    			.menuIdEq(queryVO.getMenuId()).funCodeEq(queryVO.getFunCode()).updateUserEq(queryVO.getUpdateUser())
+    			.funNameLike(queryVO.getFunName()).builderQueryWrapper();
+    	queryWrapper.orderByAsc(SaasFunction::getFunSort);
+    	List<SaasFunction> list = this.saasFunctionService.list(queryWrapper);
+    	if (CollectionUtil.isEmpty(list)) {
+			return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+    
+    /**
+     * 角色功能点列表查询,根据角色做权限过滤
+     */
+    @ApiOperation(value = "角色菜单功能点列表查询")
+    @RequestMapping(value = "querySaasRoleFunctions")
+    public ResponseResult querySaasRoleFunctions(@RequestBody @Validated SaasFunctionQueryVO queryVO) {
+    	if (StringUtil.isBlank(queryVO.getRoleId())) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "角色ID,不可为空");
+		}
+    	// 验证角色是否存在
+    	SaasRole saasRole = this.saasRoleService.getOne(queryVO.getRoleId());
+    	if (saasRole == null) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "角色信息不存在");
+		}
+    	// 优先查询出存在功能点的信息集合
+    	List<SaasFunction> functions = this.saasFunctionService.queryRoleFunctionList(queryVO.getGroupCode(), queryVO.getRoleId(), null);
+    	// 再查询出此角色下,所有不存在功能点的菜单集合
+    	List<SaasMenu> menus = this.saasMenuService.queryMenuAndEmptyFunction(queryVO.getGroupCode(), queryVO.getRoleId());
+    	
+    	JSONObject result = new JSONObject();
+    	result.put("menus", menus == null ? Lists.newArrayList() : menus);
+    	result.put("functions", functions == null ? Lists.newArrayList() : functions);
+        return ResponseResultUtil.successResult(result);
+    }
+
+    /**
+     * 新增
+     */
+	@ApiOperation(value = "保存")
+	@RequestMapping(value = "createSaasFunction")
+    public ResponseResult createSaasFunction(@RequestBody @Validated SaasFunctionCreateVO createVO) {
+		// 验证菜单ID是否存在
+		SaasMenu menu = this.saasMenuService.getById(createVO.getMenuId());
+		if (menu == null) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0320.getCode(), "不存在此菜单");
+		}
+		SaasFunction saasFunction = new SaasFunction();
+		BeanUtils.copyProperties(createVO, saasFunction);
+		saasFunction.setId(null);
+		saasFunction.setUpdateUser(createVO.getAccountId());
+        boolean result = this.saasFunctionService.save(saasFunction);
+        return result ? ResponseResultUtil.successResult("保存成功", saasFunction.getId()) : ResponseResultUtil.errorResult("保存失败");
+    }
+	
+    /**
+     * 更新
+     */
+	@ApiOperation(value = "更新")
+	@RequestMapping(value = "updateSaasFunction")
+    public ResponseResult updateSaasFunction(@RequestBody @Validated SaasFunctionCreateVO createVO) {
+		if (StringUtil.isBlank(createVO.getId())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "功能ID不可为空");
+		}
+		// 验证菜单ID是否存在
+		SaasMenu menu = this.saasMenuService.getById(createVO.getMenuId());
+		if (menu == null) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0320.getCode(), "不存在此菜单");
+		}
+		SaasFunction saasFunction = new SaasFunction();
+		BeanUtils.copyProperties(createVO, saasFunction);
+		saasFunction.setUpdateUser(createVO.getAccountId());
+        boolean result = this.saasFunctionService.updateById(saasFunction);
+        return result ? ResponseResultUtil.successResult("更新成功") : ResponseResultUtil.errorResult("更新失败");
+    }
+
+    /**
+     * 物理删除
+     */
+    @ApiOperation(value = "删除")
+    @RequestMapping(value = "deleteSaasFunction")
+    public ResponseResult deleteSaasFunction(@RequestBody @Validated SaasFunctionDeleteVO deleteVO) {
+    	if (StringUtil.isAllBlank(deleteVO.getId(), deleteVO.getMenuId())) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "功能ID与菜单ID至少存在其一");
+		}
+        boolean result = this.saasRoleMenuHandler.deleteSaasFunction(deleteVO.getId(), deleteVO.getMenuId());
+        return result ? ResponseResultUtil.successResult("删除成功") : ResponseResultUtil.errorResult("删除失败");
+    }
+    
+}

+ 158 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasGroupController.java

@@ -0,0 +1,158 @@
+package com.persagy.person.controller;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.manage.SaasAuthHandler;
+import com.persagy.person.manage.SaasGroupProjectHandler;
+import com.persagy.person.mq.CommonTopicProducer;
+import com.persagy.person.pojo.dto.SaasGroup;
+import com.persagy.person.pojo.vo.group.SaasGroupCreateVO;
+import com.persagy.person.pojo.vo.group.SaasGroupQueryVO;
+import com.persagy.person.service.ISaasGroupService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 集团信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Api(tags = "集团信息")
+@RestController
+@RequestMapping(value = "/group", method = RequestMethod.POST)
+public class SaasGroupController {
+	
+	@Autowired
+	private SaasAuthHandler saasAuthHandler;
+	
+    @Autowired
+    private ISaasGroupService saasGroupService;
+    
+	@Autowired
+	private CommonTopicProducer commonTopicProducer;
+    
+    @Autowired
+    private SaasGroupProjectHandler saasGroupProjectHandler;
+    
+    /**
+     * 列表查询
+     */
+    @ApiOperation(value = "列表查询")
+    @RequestMapping(value = "querySaasGroupList")
+    public ResponseResult querySaasGroupList(@RequestBody @Validated SaasGroupQueryVO queryVO) {
+    	// 账号数据可见性的权限鉴定
+		Map<String, String> authMap = this.saasAuthHandler.validGroupProjectAuth(queryVO.getAccountId(), queryVO.getGroupCode());
+		if (StringUtil.isNotBlank(authMap.get(SaasCommonConstant.GROUP_CODE))) {
+			queryVO.setGroupCode(authMap.get(SaasCommonConstant.GROUP_CODE));
+		}
+    	// 添加数据访问控制,账号可见域,0-所有集团项目,1-单集团所有项目(此时,集团编码需存在),2-其他
+		String accountType = authMap.get(SaasCommonConstant.ACCOUNT_TYPE);
+    	// 2-其他
+		if (SaasCommonConstant.STR_STATUS_2.equals(accountType)) {
+			SaasGroup saasGroup = new SaasGroup();
+			BeanUtils.copyProperties(queryVO, saasGroup);
+			List<SaasGroup> list = this.saasGroupService.queryAllowGroupInfo(saasGroup, queryVO.getAccountId());
+			return ResponseResultUtil.successResult(list, CollectionUtil.isEmpty(list) ? 0L : list.size());
+		}
+		List<SaasGroup> list = this.saasGroupProjectHandler.querySaasGroupList(queryVO);
+		if (CollectionUtil.isEmpty(list)) {
+			return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+    
+    /**
+     * 查询集团项目树,条件只生效账号ID和集团编码字段
+     */
+    @ApiOperation(value = "查询集团项目树")
+    @RequestMapping(value = "queryGroupProjectTree")
+    public ResponseResult queryGroupProjectTree(@RequestBody @Validated SaasGroupQueryVO queryVO) {
+    	// 账号数据可见性的权限鉴定
+		Map<String, String> authMap = this.saasAuthHandler.validGroupProjectAuth(queryVO.getAccountId(), queryVO.getGroupCode());
+		if (StringUtil.isNotBlank(authMap.get(SaasCommonConstant.GROUP_CODE))) {
+			queryVO.setGroupCode(authMap.get(SaasCommonConstant.GROUP_CODE));
+		}
+    	// 添加数据访问控制,账号可见域,0-所有集团项目,1-单集团所有项目(此时,集团编码需存在),2-其他
+		String accountType = authMap.get(SaasCommonConstant.ACCOUNT_TYPE);
+    	// 2-其他
+		if (SaasCommonConstant.STR_STATUS_2.equals(accountType)) {
+			List<SaasGroup> list = this.saasGroupProjectHandler.queryGroupProjectTree(queryVO.getAccountId(), queryVO.getGroupCode(), false);
+	        return ResponseResultUtil.successResult(list, (long)list.size());
+		}
+		List<SaasGroup> list = this.saasGroupProjectHandler.queryGroupProjectTree(queryVO.getAccountId(), queryVO.getGroupCode(), true);
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+    
+    /**
+     * 新增,同时新增权限记录,也同时新增一条未分区的区域信息
+     */
+	@ApiOperation(value = "保存")
+	@RequestMapping(value = "createSaasGroup")
+    public ResponseResult createSaasGroup(@RequestBody @Validated SaasGroupCreateVO createVO) {
+		// 验证集团名称与集团编码的分别唯一性
+		boolean exists = this.saasGroupService.validGroupCodeOrName(createVO.getGroupCode(), createVO.getGroupName(), false);
+		if (!exists) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "集团编码或集团名称已存在");
+		}
+		SaasGroup saasGroup = new SaasGroup();
+		BeanUtils.copyProperties(createVO, saasGroup);
+		saasGroup.setUpdateUser(createVO.getAccountId());
+        return this.saasGroupProjectHandler.createSaasGroup(saasGroup, createVO.getAccountId());
+    }
+    
+    /**
+     * 更新,无需新增权限记录
+     */
+	@ApiOperation(value = "更新")
+	@RequestMapping(value = "updateSaasGroup")
+    public ResponseResult updateSaasGroup(@RequestBody @Validated SaasGroupCreateVO createVO) {
+		// 验证数据是否名称是否重复
+		boolean exists = this.saasGroupService.validGroupCodeOrName(createVO.getGroupCode(), createVO.getGroupName(), true);
+		if (!exists) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "集团名称,已存在");
+		}
+		SaasGroup saasGroup = new SaasGroup();
+		BeanUtils.copyProperties(createVO, saasGroup);
+		saasGroup.setUpdateUser(createVO.getAccountId());
+		LambdaUpdateWrapper<SaasGroup> updateWrapper = new SaasGroup.Builder().createUpdateWrapper()
+				.groupCodeEq(createVO.getGroupCode()).validEq(SaasCommonConstant.STATUS_1).builderUpdateWrapper();
+		exists = this.saasGroupService.update(saasGroup, updateWrapper);
+		if (exists) {
+			this.commonTopicProducer.sendGroupInfo(saasGroup, SaasCommonConstant.UPDATE_TYPE);
+			return ResponseResultUtil.successResult("更新成功");
+		}
+        return ResponseResultUtil.errorResult("更新失败");
+    }
+
+    /**
+     * 逻辑删除
+     */
+	/*@ApiOperation(value = "删除")
+    @RequestMapping(value = "deleteSaasGroup")
+    public ResponseResult deleteSaasGroup(@RequestBody SaasGroup saasGroup) {
+        boolean result = this.saasGroupService.removeById(saasGroup.getId());
+        return result ? ResponseResultUtil.successResult("删除成功") : ResponseResultUtil.errorResult("删除失败");
+    }*/
+    
+}

+ 225 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasLoginController.java

@@ -0,0 +1,225 @@
+package com.persagy.person.controller;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.log.core.util.RequestUtil;
+import com.persagy.person.config.ApplicationProperties;
+import com.persagy.person.pojo.dto.SaasAccount;
+import com.persagy.person.pojo.vo.account.SaasAccountLoginVO;
+import com.persagy.person.pojo.vo.account.SaasAccountQueryVO;
+import com.persagy.person.service.ISaasAccountService;
+import com.persagy.security.constant.CipherConstans;
+import com.persagy.security.util.BouncycastleCipher;
+import com.persagy.security.util.SecureAES;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.crypto.digest.DigestAlgorithm;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 登录
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+
+@Api(tags = "账号信息")
+@RestController
+public class SaasLoginController {
+
+	@Autowired
+	private ApplicationProperties properties;
+	
+    @Autowired
+    private BouncycastleCipher bouncycastleCipher;
+    
+	@Autowired
+    private ISaasAccountService saasAccountService;
+	
+	@Autowired
+	private RedisTemplate<String, Object> redisTemplate;
+	
+    /**
+     * 运维系统账号登录,后续再优化token,目前不支持APP端登录
+     * 
+     * @throws UnsupportedEncodingException 
+     * @throws NumberFormatException 
+     */
+    @ApiOperation(value = "运维系统账号登录")
+    @RequestMapping(value = "saas/login", method = RequestMethod.POST)
+    public ResponseResult saasAccountLogin(@RequestBody @Validated SaasAccountLoginVO loginVO, HttpServletRequest request, HttpServletResponse response) throws NumberFormatException, UnsupportedEncodingException {
+    	LambdaQueryWrapper<SaasAccount> queryWrapper = new SaasAccount.Builder().createQueryWrapper().usernameEq(loginVO.getUsername()).passwordEq(loginVO.getPassword()).builderQueryWrapper();
+    	List<SaasAccount> accounts = this.saasAccountService.list(queryWrapper);
+    	if (CollectionUtil.isEmpty(accounts) || accounts.size() > 1) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0220.getCode(), "用户名/密码错误");
+		}
+    	SaasAccount account = accounts.get(0);
+    	// 验证此账号是否可用
+    	if (SaasCommonConstant.STATUS_1 != account.getValid()) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0220.getCode(), "此账号已停用");
+		}
+    	// 验证是否在有效期内
+    	if (SaasCommonConstant.STR_STATUS_0.equals(account.getValidLast())) {
+    		Date date = new Date();
+    		Date validEndTime = account.getValidEndTime();
+    		if (date.after(validEndTime)) {
+    			return ResponseResultUtil.errorResult(ResponseCode.A0220.getCode(), "此账号已过有效期,不允许再登录");
+			}
+		}
+    	// 如果是业务系统账号,集团编码必须存在
+    	if (SaasCommonConstant.STR_STATUS_1.equals(account.getAccountBelong()) && StringUtil.isBlank(account.getGroupCode())) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "业务系统账号,集团编码不可为空");
+		}
+    	// 更新账号登录时间,及IP
+    	String address = RequestUtil.getIpAddress(request);
+    	LambdaUpdateWrapper<SaasAccount> updateWrapper = new SaasAccount.Builder().createUpdateWrapper()
+    			.idEq(account.getId()).groupCodeEq(account.getGroupCode())
+    			.validEq(SaasCommonConstant.STATUS_1).builderUpdateWrapper();
+    	updateWrapper.set(SaasAccount::getLastLoginTime, new Date());
+    	updateWrapper.set(SaasAccount::getLastLoginIp, address);
+    	boolean result = this.saasAccountService.update(updateWrapper);
+    	if (!result) {
+    		return ResponseResultUtil.errorResult("登录信息更新失败");
+		}
+    	account.setPassword(null);
+    	String token = this.setRedisToken(account, loginVO.isRemember(), false);
+    	response.setHeader(CipherConstans.TOKEN_HEADER_TOKEN, token);
+    	return ResponseResultUtil.successResult(account);
+    }
+    
+    /**
+     * 能够进来,说明已经经过token验证,且通过,查询出账号信息,并返回即可
+     * 
+     * @param queryVO
+     * @return
+     * @throws NumberFormatException
+     * @throws UnsupportedEncodingException
+     */
+    @ApiOperation(value = "记住登录")
+    @RequestMapping(value = "saas/remember", method = RequestMethod.POST)
+    public ResponseResult saasAccountLogin(@RequestBody @Validated SaasAccountQueryVO queryVO, HttpServletRequest request, HttpServletResponse response) throws NumberFormatException, UnsupportedEncodingException {
+    	if (StringUtil.isAllBlank(queryVO.getAccountId(), queryVO.getUsername(), queryVO.getGroupCode())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "账号ID、账号用户名与集团编码,至少存在其一");
+		}
+    	SaasAccount account = this.saasAccountService.getOne(queryVO.getAccountId(), queryVO.getGroupCode(), queryVO.getUsername());
+    	if (account == null) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "账号信息不存在");
+		}
+    	String token = this.setRedisToken(account, true, true);
+    	response.setHeader(CipherConstans.TOKEN_HEADER_TOKEN, token);
+    	return ResponseResultUtil.successResult(account);
+    }
+    
+    /**
+     * 退出登录,清空token,因为网关以确保token值必须于此账号,这里直接清空
+     * 
+     * @param queryVO
+     * @return
+     * @throws NumberFormatException
+     * @throws UnsupportedEncodingException
+     */
+    @ApiOperation(value = "退出登录")
+    @RequestMapping(value = "account/logout", method = RequestMethod.POST)
+    public ResponseResult accountLogout(@RequestBody @Validated SaasAccountQueryVO queryVO) throws NumberFormatException, UnsupportedEncodingException {
+    	if (StringUtil.isBlank(queryVO.getAccountId())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "账号ID,不可为空");
+		}
+    	// 从redis中清空此账号的sign信息
+    	boolean remove = this.bouncycastleCipher.remove(queryVO.getAccountId());
+    	return remove ? ResponseResultUtil.successResult("退出成功") : ResponseResultUtil.errorResult("退出失败");
+    }
+    
+    /**
+     * 设置此账号的token,存入redis,如果redis中已存在,只追加有效期
+     * @param account
+     * @param remember
+     * @param isEqual 是否验证一致
+     * @return
+     * @throws UnsupportedEncodingException
+     */
+    private String setRedisToken(SaasAccount account, boolean remember, boolean isEqual) throws UnsupportedEncodingException {
+    	// 生成token,并验证之前登录是否为记住登录
+    	SecureAES aes = new SecureAES(properties.getAesKey(), properties.getAesIv());
+    	// 对称性加密用户信息
+    	String data = aes.encryptAccount(this.tokenAccountInfo(account, remember));
+    	// token存在判断
+    	String sign = (String)this.redisTemplate.opsForValue().get(account.getId());
+    	if (sign != null) {
+    		if (isEqual) {
+	    		// 判断是否与redis中一致,不一致,返回错误信息
+	        	boolean result = this.bouncycastleCipher.isEqual(sign, account.getId());
+	        	if (!result) {
+	        		throw new BusinessException("该账户未登录,请先登录");
+	    		}
+			}
+			this.redisTemplate.expire(account.getId(), Long.parseLong(this.properties.getTokenExpire()), TimeUnit.HOURS);
+		} else {
+			// 加密串MD5加密转为sign,redis:key-账号ID,value-sign(data-MD5加密后)
+	    	sign = this.bouncycastleCipher.encrypt(this.tokenInfo(data), account.getId(), DigestAlgorithm.MD5, Long.parseLong(this.properties.getTokenExpire()), TimeUnit.HOURS);
+		}
+        // token=data.sign
+    	String token = data + SaasCommonConstant.POINT_JOIN_SYMBOL + sign;
+        return token;
+    }
+    
+    /**
+     * 账号信息
+     * 
+     * @param groupCode
+     * @param appId
+     * @param accountId
+     * @param accountBelong
+     * @return
+     */
+    private JSONObject tokenAccountInfo(SaasAccount saasAccount, boolean remember) {
+		JSONObject object = new JSONObject();
+		object.put(SaasCommonConstant.REMEMBER, remember);
+		object.put(SaasCommonConstant.GROUP_CODE, saasAccount.getGroupCode());
+		object.put(SaasCommonConstant.APP_ID, saasAccount.getAppId());
+		object.put(SaasCommonConstant.ACCOUNT_ID, saasAccount.getId());
+		return object;
+	}
+    
+    /**
+     * 账号信息
+     * 
+     * @param groupCode
+     * @param appId
+     * @param accountId
+     * @param accountBelong
+     * @return
+     */
+    private String tokenInfo(String content) {
+		JSONObject object = new JSONObject();
+		object.put("date", System.currentTimeMillis());
+		object.put("content", content);
+		return object.toJSONString();
+	}
+    
+}

+ 168 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasMenuController.java

@@ -0,0 +1,168 @@
+package com.persagy.person.controller;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.manage.SaasAuthHandler;
+import com.persagy.person.manage.SaasRoleMenuHandler;
+import com.persagy.person.pojo.dto.SaasMenu;
+import com.persagy.person.pojo.vo.menu.SaasMenuCreateVO;
+import com.persagy.person.pojo.vo.menu.SaasMenuDeleteVO;
+import com.persagy.person.pojo.vo.menu.SaasMenuQueryVO;
+import com.persagy.person.service.ISaasMenuService;
+import com.persagy.person.service.ISaasRoleMenuService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 菜单信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Api(tags = "菜单信息")
+@RestController
+@RequestMapping(value = "/menu", method = RequestMethod.POST)
+public class SaasMenuController {
+	
+	@Autowired
+	private SaasAuthHandler saasAuthHandler;
+	
+    @Autowired
+    private ISaasMenuService saasMenuService;
+    
+    @Autowired
+    private SaasRoleMenuHandler saasRoleMenuHandler;
+    
+    @Autowired
+    private ISaasRoleMenuService saasRoleMenuService;
+    
+    /**
+     * 查询账号菜单功能权限树,根据账号ID做权限过滤,主要供账号登录后左侧展示使用
+     */
+    @ApiOperation(value = "查询账号菜单功能权限树")
+    @RequestMapping(value = "querySaasMenuTree")
+    public ResponseResult querySaasMenuTree(@RequestBody @Validated SaasMenuQueryVO queryVO) {
+    	// 获取此账号对应的菜单范围
+    	Map<String, String> menuAuth = this.saasAuthHandler.validSaasMenuAuth(queryVO.getAccountId(), queryVO.getGroupCode());
+    	if (StringUtil.isNotBlank(menuAuth.get(SaasCommonConstant.GROUP_CODE))) {
+    		queryVO.setGroupCode(menuAuth.get(SaasCommonConstant.GROUP_CODE));
+		}
+    	// 添加数据访问控制,账号可见域,0-所有集团项目,1-单集团所有项目(此时,集团编码需存在),2-其他
+    	String accountType = menuAuth.get(SaasCommonConstant.ACCOUNT_TYPE);
+    	// 账号所属,0-运维系统,1-业务系统账号
+    	String accountBelong = menuAuth.get(SaasCommonConstant.ACCOUNT_BELONG);
+    	List<SaasMenu> menuTree = null;
+    	if (SaasCommonConstant.STR_STATUS_0.equals(accountType) && SaasCommonConstant.STR_STATUS_0.equals(accountBelong)) {
+    		// 如果是运维系统的账号,accountType为0的情况下查询所有菜单权限,其余情况走表关联查询,为1时,后续可添加
+    		menuTree = this.saasRoleMenuHandler.querySaasMenuTree(null, null, true, queryVO.isMenu());
+    	} else {
+    		menuTree = this.saasRoleMenuHandler.querySaasMenuTree(queryVO.getAccountId(), queryVO.getGroupCode(), false, queryVO.isMenu());
+		}
+    	return ResponseResultUtil.successResult(menuTree);
+    }
+    
+    /**
+     * 查询菜单功能树,角色配置使用
+     */
+    @ApiOperation(value = "查询菜单功能树")
+    @RequestMapping(value = "queryMenuFunTree")
+    public ResponseResult queryMenuFunTree(@RequestBody @Validated SaasMenuQueryVO queryVO) {
+    	if (StringUtil.isBlank(queryVO.getMenuType())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "菜单类型不可为空");
+		}
+    	// 这里按照超管的逻辑进行处理,因为不会做权限过滤
+		LambdaQueryWrapper<SaasMenu> queryWrapper = new SaasMenu.Builder().createQueryWrapper().idEq(queryVO.getMenuId())
+				.menuTypeEq(queryVO.getMenuType()).appIdEq(queryVO.getAppId()).builderQueryWrapper();
+		List<SaasMenu> menuTree = this.saasMenuService.list(queryWrapper);
+		if (CollectionUtil.isEmpty(menuTree)) {
+			return ResponseResultUtil.successResult(Lists.newArrayList());
+		}
+		// 2.转为菜单树
+		List<SaasMenu> topMenus = new ArrayList<SaasMenu>();
+		for (int i = menuTree.size() - 1; i >= 0; i--) {
+			SaasMenu saasMenu = menuTree.get(i);
+			if (StringUtil.isBlank(saasMenu.getParentId())) {
+				topMenus.add(saasMenu);
+				menuTree.remove(i);
+			}
+		}
+		List<SaasMenu> parents = topMenus.stream().sorted(Comparator.comparing(SaasMenu::getMenuSort)).collect(Collectors.toList());
+		this.saasRoleMenuHandler.setMenuChildrens(null, menuTree, parents, true, true);
+    	return ResponseResultUtil.successResult(parents);
+    }
+    
+    /**
+     * 新增
+     */
+	@ApiOperation(value = "保存")
+	@RequestMapping(value = "createSaasMenu")
+    public ResponseResult createSaasMenu(@RequestBody @Validated SaasMenuCreateVO createVO) {
+		if (StringUtil.isNotBlank(createVO.getMenuUrl()) && StringUtil.isEmpty(createVO.getUrlType())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "当菜单URL存在时,URL类型不可为空");
+		}
+		SaasMenu saasMenu = new SaasMenu();
+		BeanUtils.copyProperties(createVO, saasMenu);
+		saasMenu.setId(null);
+		saasMenu.setUpdateUser(createVO.getAccountId());
+        boolean result = this.saasMenuService.save(saasMenu);
+        return result ? ResponseResultUtil.successResult("保存成功", saasMenu.getId()) : ResponseResultUtil.errorResult("保存失败");
+    }
+    
+    /**
+     * 更新
+     */
+	@ApiOperation(value = "更新")
+	@RequestMapping(value = "updateSaasMenu")
+    public ResponseResult updateSaasMenu(@RequestBody @Validated SaasMenuCreateVO createVO) {
+		if (StringUtil.isBlank(createVO.getId())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "菜单ID不可为空");
+		}
+		if (StringUtil.isNotBlank(createVO.getMenuUrl()) && StringUtil.isEmpty(createVO.getUrlType())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "当菜单URL存在时,URL类型不可为空");
+		}
+		SaasMenu saasMenu = new SaasMenu();
+		BeanUtils.copyProperties(createVO, saasMenu);
+		saasMenu.setUpdateUser(createVO.getAccountId());
+        boolean result = saasMenuService.updateById(saasMenu);
+        return result ? ResponseResultUtil.successResult("更新成功") : ResponseResultUtil.errorResult("更新失败");
+    }
+
+    /**
+     * 物理删除
+     */
+    @ApiOperation(value = "删除")
+    @RequestMapping(value = "deleteSaasMenu")
+    public ResponseResult deleteSaasMenu(@RequestBody @Validated SaasMenuDeleteVO deleteVO) {
+    	// 只有此菜单不属于任何可用的角色才允许被删除
+    	boolean result = this.saasRoleMenuService.isAllowDeleteMenu(deleteVO.getGroupCode(), deleteVO.getId());
+    	if (!result) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "该菜单已被使用,不允许被删除");
+		}
+    	result = this.saasRoleMenuHandler.deleteSaasMenu(deleteVO.getId());
+        return result ? ResponseResultUtil.successResult("删除成功") : ResponseResultUtil.errorResult("删除失败");
+    }
+    
+}

+ 348 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasProjectController.java

@@ -0,0 +1,348 @@
+package com.persagy.person.controller;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.common.model.BaseUserModel;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.log.core.annotation.IgnoreLog;
+import com.persagy.person.manage.SaasAreaProjectHandler;
+import com.persagy.person.manage.SaasAuthHandler;
+import com.persagy.person.manage.SaasGroupProjectHandler;
+import com.persagy.person.manage.SaasProjectExcelDataHandler;
+import com.persagy.person.manage.SaasProjectSheetWriteHandler;
+import com.persagy.person.pojo.dto.SaasAccountProject;
+import com.persagy.person.pojo.dto.SaasArea;
+import com.persagy.person.pojo.dto.SaasGroup;
+import com.persagy.person.pojo.dto.SaasProject;
+import com.persagy.person.pojo.vo.BaseGroupVO;
+import com.persagy.person.pojo.vo.group.SaasGroupQueryVO;
+import com.persagy.person.pojo.vo.project.SaasProjectAreaUpdateVO;
+import com.persagy.person.pojo.vo.project.SaasProjectCreateVO;
+import com.persagy.person.pojo.vo.project.SaasProjectExcel;
+import com.persagy.person.pojo.vo.project.SaasProjectPageVO;
+import com.persagy.person.pojo.vo.project.SaasProjectQueryVO;
+import com.persagy.person.service.ISaasAccountProjectService;
+import com.persagy.person.service.ISaasAreaService;
+import com.persagy.person.service.ISaasGroupService;
+import com.persagy.person.service.ISaasProjectService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Slf4j
+@Api(tags = "项目信息")
+@RestController
+@RequestMapping(value = "/project", method = RequestMethod.POST)
+public class SaasProjectController {
+	
+	@Autowired
+	private SaasAuthHandler saasAuthHandler;
+	
+    @Autowired
+    private ISaasAreaService saasAreaService;
+    
+    @Autowired
+    private ISaasGroupService saasGroupService;
+    
+    @Autowired
+    private ISaasProjectService saasProjectService;
+
+    @Autowired
+    private SaasAreaProjectHandler saasAreaProjectHandler;
+    
+    @Autowired
+    private SaasGroupProjectHandler saasGroupProjectHandler;
+    
+    @Autowired
+    private ISaasAccountProjectService saasAccountProjectService;
+    
+    /**
+     * 项目信息查询,更新时间降序
+     */
+    @ApiOperation(value = "项目信息查询")
+    @RequestMapping(value = "querySaasProjectList")
+    public ResponseResult querySaasProjectList(@RequestBody @Validated SaasProjectQueryVO queryVO) {
+    	if (CollectionUtil.isNotEmpty(queryVO.getProjectIds()) && queryVO.getProjectIds().size() > 999) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "项目ID集合数量过大,请分批查询");
+		}
+    	SaasProject saasProject = new SaasProject();
+		BeanUtils.copyProperties(queryVO, saasProject);
+        Page<SaasProject> projectList = this.saasGroupProjectHandler.querySaasProjectList(saasProject, null, null);
+        return ResponseResultUtil.successResult(projectList.getRecords(), projectList.getTotal());
+    }
+    
+    /**
+     * 项目-区域平铺列表查询,权限过滤
+     */
+    @ApiOperation(value = "区域-项目平铺列表查询")
+    @RequestMapping(value = "queryGroupProjectList")
+    public ResponseResult queryGroupProjectList(@RequestBody @Validated BaseGroupVO queryVO) {
+    	LambdaQueryWrapper<SaasAccountProject> queryWrapper = new SaasAccountProject.Builder().createQueryWrapper()
+    			.groupCodeEq(queryVO.getGroupCode()).accountIdEq(queryVO.getAccountId()).builderQueryWrapper();
+    	List<SaasAccountProject> list = this.saasAccountProjectService.list(queryWrapper);
+    	if (list == null) {
+    		return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+    
+    /**
+     * 项目信息分页查询, 更新时间降序
+     */
+    @ApiOperation(value = "项目信息分页查询")
+    @RequestMapping(value = "queryProjectPageList")
+    public ResponseResult queryProjectPageList(@RequestBody @Validated SaasProjectPageVO pageVO) {
+    	SaasProject saasProject = new SaasProject();
+		BeanUtils.copyProperties(pageVO, saasProject);
+    	Page<SaasProject> projectList = this.saasGroupProjectHandler.querySaasProjectList(saasProject, pageVO.getPage(), pageVO.getSize());
+    	return ResponseResultUtil.successResult(projectList.getRecords(), projectList.getTotal());
+    }
+    
+    /**
+     * 区域项目信息查询,结构:集团->区域->项目, 未做权限过滤
+     */
+    @ApiOperation(value = "查询集团区域项目信息")
+    @RequestMapping(value = "queryAreaProjectTree")
+    public ResponseResult queryAreaProjectTree(@RequestBody @Validated SaasProjectQueryVO model) {
+    	// 获取集团信息
+    	List<SaasGroup> groups = null;
+    	if (StringUtil.isBlank(model.getGroupCode())) {
+			// 获取所有集团
+    		LambdaQueryWrapper<SaasGroup> queryWrapper = new SaasGroup.Builder().createQueryWrapper().validEq(SaasCommonConstant.STATUS_1).builderQueryWrapper();
+    		groups = this.saasGroupService.list(queryWrapper);
+		} else {
+			SaasGroup group = this.saasGroupService.getOne(model.getGroupCode());
+			if (group == null) {
+				return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "集团信息不存在");
+			}
+			groups = Lists.newArrayList(group);
+		}
+    	if (CollectionUtil.isEmpty(groups)) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "集团信息不存在");
+		}
+    	for (SaasGroup saasGroup : groups) {
+    		this.saasAreaProjectHandler.queryAreaProjectTree(saasGroup);
+		}
+    	return ResponseResultUtil.successResult(groups);
+    }
+    
+    /**
+     * 区域项目信息查询,结构:集团->区域->项目, 根据账号ID做了权限过滤
+     */
+    @ApiOperation(value = "查询区域项目信息")
+    @RequestMapping(value = "queryAllowAreaProjectTree")
+    public ResponseResult queryAllowAreaProjectTree(@RequestBody @Validated SaasProjectQueryVO queryVO) {
+    	if (CollectionUtil.isNotEmpty(queryVO.getProjectIds()) && queryVO.getProjectIds().size() > 999) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "项目ID集合数量过大,请分批查询");
+		}
+    	// 账号数据可见性的权限鉴定
+		Map<String, String> authMap = this.saasAuthHandler.validGroupProjectAuth(queryVO.getAccountId(), queryVO.getGroupCode());
+		if (StringUtil.isNotBlank(authMap.get(SaasCommonConstant.GROUP_CODE))) {
+			queryVO.setGroupCode(authMap.get(SaasCommonConstant.GROUP_CODE));
+		}
+    	// 添加数据访问控制,账号可见域,0-所有集团项目,1-单集团所有项目(此时,集团编码需存在),2-其他
+		String accountType = authMap.get(SaasCommonConstant.ACCOUNT_TYPE);
+		List<SaasGroup> groups = this.saasAuthHandler.getAllowGroupList(queryVO.getAccountId(), queryVO.getGroupCode(), accountType);
+    	// 查询区域项目树
+    	for (SaasGroup saasGroup : groups) {
+    		List<SaasArea> areaList = this.saasAuthHandler.getAllowAreaList(queryVO.getAccountId(), queryVO.getGroupCode(), accountType);
+    		saasGroup.setAreas(areaList);
+    		this.saasAreaProjectHandler.queryAllowAreaProjectTree(queryVO, saasGroup, areaList);
+		}
+    	return ResponseResultUtil.successResult(groups);
+    }
+    
+    /**
+     * 新增,集团编码与项目ID联合唯一,同时判断是否需要新增一条权限信息
+     */
+	@ApiOperation(value = "保存")
+	@RequestMapping(value = "createSaasProject")
+    public ResponseResult createSaasProject(@RequestBody @Validated SaasProjectCreateVO createVO) {
+		SaasProject saasProject = new SaasProject();
+		BeanUtils.copyProperties(createVO, saasProject);
+		saasProject.setUpdateUser(createVO.getAccountId());
+		saasProject.setId(null);
+		if (StringUtil.isBlank(createVO.getAreaId())) {
+			// 查询出未分区的区域ID
+			SaasArea areaOne = this.saasAreaService.getAreaOne(null, createVO.getGroupCode(), SaasCommonConstant.STR_STATUS_MINUS_1, null);
+			if (areaOne == null) {
+				return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "此项目所属集团不存在未分区区域,请检查"); 
+			}
+			saasProject.setAreaId(areaOne.getId());
+		}
+		
+		// 验证集团编码与项目ID的联合唯一性
+		boolean exists = this.saasProjectService.validProjectData(saasProject, false);
+		if (!exists) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "项目ID、项目本地编码、项目名称都必须唯一");
+		}
+		return this.saasGroupProjectHandler.createSaasProject(saasProject, createVO.getAccountId());
+    }
+    
+    /**
+     * 更新
+     */
+	@ApiOperation(value = "更新")
+	@RequestMapping(value = "updateSaasProject")
+    public ResponseResult updateSaasProject(@RequestBody @Validated SaasProjectCreateVO createVO) {
+		if (StringUtil.isBlank(createVO.getId())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "主键ID不可为空");
+		}
+		SaasProject saasProject = new SaasProject();
+		BeanUtils.copyProperties(createVO, saasProject);
+		saasProject.setUpdateUser(createVO.getAccountId());
+		if (SaasCommonConstant.STR_STATUS_MINUS_1.equals(createVO.getAreaId())) {
+			// 查询出未分区的区域ID
+			SaasArea areaOne = this.saasAreaService.getAreaOne(null, createVO.getGroupCode(), SaasCommonConstant.STR_STATUS_MINUS_1, null);
+			if (areaOne == null) {
+				return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "此项目所属集团不存在未分区区域,请检查"); 
+			}
+			saasProject.setAreaId(areaOne.getId());
+		}
+		// 验证集团编码与项目ID的联合唯一性
+		boolean exists = this.saasProjectService.validProjectData(saasProject, true);
+		if (!exists) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "项目名称或项目ID或项目本地编码已存在");
+		}
+		LambdaUpdateWrapper<SaasProject> updateWrapper = new SaasProject.Builder().createUpdateWrapper()
+				.idEq(createVO.getId()).groupCodeEq(createVO.getGroupCode()).projectIdEq(createVO.getProjectId())
+				.validEq(SaasCommonConstant.STATUS_1).builderUpdateWrapper();
+		exists = this.saasProjectService.update(saasProject, updateWrapper);
+        return exists ? ResponseResultUtil.successResult("更新成功") : ResponseResultUtil.errorResult("更新失败");
+    }
+	
+	/**
+	 * 批量变更项目所属区域
+	 */
+	@ApiOperation(value = "批量变更项目所属区域")
+	@RequestMapping(value = "batchUpdateProjectArea")
+    public ResponseResult batchUpdateProjectArea(@RequestBody @Validated SaasProjectAreaUpdateVO batchVO) {
+		if (batchVO.getProjectIds().size() > 100) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "项目ID过多,请多次处理");
+		}
+		SaasProject saasProject = new SaasProject();
+		BeanUtils.copyProperties(batchVO, saasProject);
+		saasProject.setUpdateUser(batchVO.getAccountId());
+		boolean result = this.saasProjectService.batchUpdateProjectArea(saasProject, batchVO.getProjectIds());
+        return result ? ResponseResultUtil.successResult("更新成功") : ResponseResultUtil.errorResult("更新失败");
+    }
+
+    /**
+     * 物理删除
+     */
+    /*@ApiOperation(value = "删除")
+    @RequestMapping(value = "deleteSaasProject")
+    public ResponseResult deleteSaasProject(@RequestBody SaasProject saasProject) {
+        boolean result = saasProjectService.removeById(saasProject.getId());
+        return result ? ResponseResultUtil.successResult("删除成功") : ResponseResultUtil.errorResult("删除失败");
+    }*/
+	
+	
+	/******************************************************** upload file *****************************************************/
+	
+	/**
+	 * 项目数据上传模板下载
+	 * 
+	 * @param baseVO
+	 * @param response
+	 * @return
+	 */
+	@ApiOperation(value = "项目数据上传模板下载")
+    @RequestMapping(value = "downloadProjectTemplate")
+	public void downloadProjectTemplate(@RequestBody @Validated BaseUserModel baseVO, HttpServletResponse response) {
+		// 优先判断是否存在集团信息
+		SaasGroupQueryVO groupVO = new SaasGroupQueryVO();
+		List<SaasGroup> list = this.saasGroupProjectHandler.querySaasGroupList(groupVO);
+		if (CollectionUtil.isEmpty(list)) {
+			throw new BusinessException("集团信息为空,请先添加集团");
+		}
+		
+		ExcelWriter excelWriter = null;
+		try {
+            response.setContentType("application/vnd.ms-excel");
+            String encode = StandardCharsets.UTF_8.name();
+            response.setCharacterEncoding(encode);
+            // 防止中文乱码
+            String fileName = URLEncoder.encode("仪表批量上传模板", encode);
+            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
+            
+            EasyExcel.write(response.getOutputStream(), SaasProjectExcel.class)
+            	.registerWriteHandler(new SaasProjectSheetWriteHandler(saasGroupProjectHandler, saasAreaProjectHandler))
+            	.sheet("传项目信息").doWrite(SaasProjectExcel.getDemoData());
+            
+           /* excelWriter = EasyExcel.write(response.getOutputStream()).build();
+            WriteSheet writeSheetOne = EasyExcel.writerSheet(0, SaasProjectExcel.SHEET_NAME_0)
+            		.registerWriteHandler(new SaasProjectSheetWriteHandler(saasGroupProjectHandler, saasAreaProjectHandler))
+            		.head(SaasProjectExcel.class).build();
+            excelWriter.write(SaasProjectExcel.getDemoData(), writeSheetOne);*/
+		} catch(Exception e) {
+			log.error("项目数据上传模板下载失败", e);
+		} finally {
+			if (excelWriter != null) {
+				excelWriter.finish();
+			}
+		}
+	}
+	
+	/**
+	 * 项目数据上传
+	 * 
+	 * @param model
+	 * @param file
+	 * @return
+	 */
+	@IgnoreLog
+	@ApiOperation(value = "项目数据直接上传")
+    @RequestMapping(value = "directUploadProjectData")
+	public ResponseResult directUploadProjectData(@ModelAttribute @Validated BaseUserModel model, MultipartFile file) {
+		try {
+			if (file == null) {
+				return ResponseResultUtil.errorResult("未找到对应文件");
+			}
+        	EasyExcel.read(file.getInputStream(), SaasProjectExcel.class, 
+        			new SaasProjectExcelDataHandler(model, saasAreaService, saasProjectService)).sheet(0).doRead();
+        	return ResponseResultUtil.successResult();
+		} catch(IOException e) {
+			log.error("传感器数据流读取失败", e);
+		}
+		return ResponseResultUtil.errorResult();
+	}
+    
+}

+ 226 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasRoleController.java

@@ -0,0 +1,226 @@
+package com.persagy.person.controller;
+
+import java.util.List;
+
+import com.persagy.person.pojo.vo.role.*;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.manage.SaasRoleMenuHandler;
+import com.persagy.person.pojo.dto.SaasGroup;
+import com.persagy.person.pojo.dto.SaasRole;
+import com.persagy.person.service.ISaasAccountRoleService;
+import com.persagy.person.service.ISaasGroupService;
+import com.persagy.person.service.ISaasRoleMenuService;
+import com.persagy.person.service.ISaasRoleService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 角色信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+
+@Api(tags = "角色信息")
+@RestController
+@RequestMapping(value = "/role", method = RequestMethod.POST)
+public class SaasRoleController {
+	
+    @Autowired
+    private ISaasRoleService saasRoleService;
+    
+    @Autowired
+    private ISaasGroupService saasGroupService;
+    
+    @Autowired
+    private SaasRoleMenuHandler saasRoleMenuHandler;
+    
+    @Autowired
+    private ISaasRoleMenuService saasRoleMenuService;
+    
+    @Autowired
+    private ISaasAccountRoleService saasAccountRoleService;
+    
+    /**
+     * 查询角色信息
+     */
+    @ApiOperation(value = "查询角色信息")
+    @RequestMapping(value = "querySaasRoleList")
+    public ResponseResult querySaasRoleList(@RequestBody @Validated SaasRoleQueryVO queryVO) {
+    	LambdaQueryWrapper<SaasRole> queryWrapper = new SaasRole.Builder().createQueryWrapper().idEq(queryVO.getId())
+    			.idIn(queryVO.getRoleIds()).roleCodeEq(queryVO.getRoleCode()).roleNameLike(queryVO.getRoleName())
+    			.groupCodeEq(queryVO.getGroupCode()).roleTypeEq(queryVO.getRoleType()).updateUserEq(queryVO.getUpdateUser())
+    			.validEq(queryVO.getValid()).builderQueryWrapper();
+    	queryWrapper.orderByDesc(SaasRole::getUpdateTime);		// 默认更新时间降序
+    	List<SaasRole> list = this.saasRoleService.list(queryWrapper);
+    	if (CollectionUtil.isEmpty(list)) {
+			return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+    	// 额外信息补充
+    	if (queryVO.isCountMenu() || queryVO.isCountFunction()) {
+			for (SaasRole saasRole : list) {
+				if (queryVO.isCountFunction()) {
+					saasRole.setCountFunction(this.saasRoleMenuService.countFunction(saasRole.getId(), null));
+				}
+				if (queryVO.isCountMenu()) {
+					saasRole.setCountMenu(this.saasRoleMenuService.countMenu(saasRole.getId()));
+				}
+			}
+		}
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+    
+    /**
+     * 分页查询角色信息
+     */
+    @ApiOperation(value = "分页查询角色信息")
+    @RequestMapping(value = "queryRolePageList")
+    public ResponseResult queryRolePageList(@RequestBody @Validated SaasRolePageVO pageVO) {
+    	Page<SaasRole> page = new Page<SaasRole>(pageVO.getPage(), pageVO.getSize());
+    	LambdaQueryWrapper<SaasRole> queryWrapper = new SaasRole.Builder().createQueryWrapper().idEq(pageVO.getId())
+    			.roleCodeEq(pageVO.getRoleCode()).roleNameLike(pageVO.getRoleName()).roleTypeEq(pageVO.getRoleType())
+    			.groupCodeEq(pageVO.getGroupCode()).updateUserEq(pageVO.getUpdateUser()).validEq(pageVO.getValid()).builderQueryWrapper();
+    	queryWrapper.orderByDesc(SaasRole::getUpdateTime);							// 默认更新时间降序
+    	Page<SaasRole> pageList = this.saasRoleService.page(page, queryWrapper);
+    	if (pageList == null || CollectionUtil.isEmpty(pageList.getRecords())) {
+    		return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+    	// 额外信息补充
+    	List<SaasRole> records = pageList.getRecords();
+    	// 额外信息补充
+    	if (pageVO.isCountMenu() || pageVO.isCountFunction()) {
+			for (SaasRole saasRole : records) {
+				if (pageVO.isCountFunction()) {
+					saasRole.setCountFunction(this.saasRoleMenuService.countFunction(saasRole.getId(), null));
+				}
+				if (pageVO.isCountMenu()) {
+					saasRole.setCountMenu(this.saasRoleMenuService.countMenu(saasRole.getId()));
+				}
+			}
+		}
+    	return ResponseResultUtil.successResult(records, pageList.getTotal());
+    }
+
+    /**
+     * 新增 角色名称唯一
+     */
+	@ApiOperation(value = "保存")
+	@RequestMapping(value = "createSaasRole")
+    public ResponseResult createSaasRole(@RequestBody @Validated SaasRoleCreateVO createVO) {
+		if (!SaasCommonConstant.STR_STATUS_0.equals(createVO.getRoleType())) {
+			// 非系统角色,一定存在集团编码
+			if (StringUtil.isBlank(createVO.getGroupCode())) {
+				return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "集团编码必须存在");
+			}
+			// 验证集团信息是否存在
+			SaasGroup saasGroup = this.saasGroupService.getOne(createVO.getGroupCode());
+			if (saasGroup == null) {
+				return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "集团信息不存在");
+			}
+		}
+		// 角色名称集团下唯一
+		boolean result = this.saasRoleService.validRoleName(createVO.getGroupCode(), createVO.getRoleName(), null);
+		if (!result) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "角色名称已存在");
+		}
+        SaasRole saasRole = new SaasRole();
+        BeanUtils.copyProperties(createVO, saasRole);
+        saasRole.setId(null);
+        saasRole.setUpdateUser(createVO.getAccountId());
+        
+        result = this.saasRoleMenuHandler.createSaasRole(saasRole, createVO.getAuths());
+        return result ? ResponseResultUtil.successResult("保存成功", saasRole.getId()) : ResponseResultUtil.errorResult("保存失败");
+    }
+    
+    /**
+     * 更新
+     */
+	@ApiOperation(value = "更新")
+	@RequestMapping(value = "updateSaasRole")
+    public ResponseResult updateSaasRole(@RequestBody @Validated SaasRoleCreateVO createVO) {
+		if (StringUtil.isBlank(createVO.getId())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "角色ID不可为空");
+		}
+		if (!SaasCommonConstant.STR_STATUS_0.equals(createVO.getRoleType())) {
+			// 非系统角色,一定存在集团编码
+			if (StringUtil.isBlank(createVO.getGroupCode())) {
+				return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "集团编码必须存在");
+			}
+			// 验证集团信息是否存在
+			SaasGroup saasGroup = this.saasGroupService.getOne(createVO.getGroupCode());
+			if (saasGroup == null) {
+				return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "集团信息不存在");
+			}
+		}
+		// 角色名称集团下唯一
+		boolean result = this.saasRoleService.validRoleName(createVO.getGroupCode(), createVO.getRoleName(), createVO.getId());
+		if (!result) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "角色名称已存在");
+		}
+		// 验证数据是否存在
+		SaasRole role = this.saasRoleService.getOne(createVO.getId());
+		if (role == null) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0320.getCode(), "角色信息不存在");
+		}
+		SaasRole saasRole = new SaasRole();
+        BeanUtils.copyProperties(createVO, saasRole);
+        saasRole.setUpdateUser(createVO.getAccountId());
+        
+        result = this.saasRoleMenuHandler.updateSaasRole(saasRole, createVO.getAuths());
+        return result ? ResponseResultUtil.successResult("更新成功") : ResponseResultUtil.errorResult("更新失败");
+    }
+
+    /**
+     * 物理删除,验证是否允许被删除,即该角色不被任何账号使用,且非业务超管角色
+     */
+    @ApiOperation(value = "删除")
+    @RequestMapping(value = "deleteSaasRole")
+    public ResponseResult deleteSaasRole(@RequestBody @Validated SaasRoleDeleteVO deleteVO) {
+    	// 验证是否允许被删除
+    	boolean result = this.saasAccountRoleService.isAllowDeleteRole(deleteVO.getGroupCode(), deleteVO.getId());
+    	if (!result) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "该角色已被使用,不允许被删除");
+		}
+    	result = this.saasRoleMenuHandler.deleteSaasRole(deleteVO);
+        return result ? ResponseResultUtil.successResult("删除成功") : ResponseResultUtil.errorResult("删除失败");
+    }
+
+
+    /**
+     * 根据角色名称查询角色信息
+     */
+    @ApiOperation(value = "根据角色名称查询角色信息")
+    @RequestMapping(value = "querySaasRoleByName")
+    public ResponseResult querySaasRoleByName(@RequestBody @Validated SaasRoleQueryByNameVO queryVO) {
+        SaasRole saasRole = new SaasRole();
+        BeanUtils.copyProperties(queryVO,saasRole);
+        LambdaQueryWrapper<SaasRole> queryWrapper = new SaasRole.Builder().createQueryWrapper()
+        .groupCodeEq(saasRole.getGroupCode()).roleNameEq(queryVO.getRoleName()).builderQueryWrapper();
+        queryWrapper.orderByDesc(SaasRole::getUpdateTime);		// 默认更新时间降序
+        List<SaasRole> list = this.saasRoleService.list(queryWrapper);
+        if (CollectionUtil.isEmpty(list)) {
+            return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+        }
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+    
+}

+ 99 - 0
saas-account/src/main/java/com/persagy/person/controller/SaasRoleMenuController.java

@@ -0,0 +1,99 @@
+package com.persagy.person.controller;
+
+import java.util.List;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.google.common.collect.Lists;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.person.manage.SaasRoleMenuHandler;
+import com.persagy.person.pojo.dto.SaasRoleMenu;
+import com.persagy.person.pojo.vo.auth.SaasRoleMenuBatchVO;
+import com.persagy.person.pojo.vo.auth.SaasRoleMenuCreateVO;
+import com.persagy.person.pojo.vo.auth.SaasRoleMenuQueryVO;
+import com.persagy.person.service.ISaasRoleMenuService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 角色-菜单功能关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+
+@Api(tags = "角色-菜单功能关联信息")
+@RestController
+@RequestMapping(value = "/roleMenu", method = RequestMethod.POST)
+public class SaasRoleMenuController {
+	
+    @Autowired
+    private SaasRoleMenuHandler saasRoleMenuHandler;
+    
+    @Autowired
+    private ISaasRoleMenuService saasRoleMenuService;
+    
+    /**
+     * 查询角色-菜单功能关联信息
+     */
+    @ApiOperation(value = "查询角色-菜单功能关联信息")
+    @RequestMapping(value = "querySaasRoleMenuList")
+    public ResponseResult querySaasRoleMenuList(@RequestBody @Validated SaasRoleMenuQueryVO queryVO) {
+    	LambdaQueryWrapper<SaasRoleMenu> queryWrapper = new SaasRoleMenu.Builder().createQueryWrapper()
+    			.groupCodeEq(queryVO.getGroupCode()).roleIdEq(queryVO.getRoleId()).menuIdEq(queryVO.getMenuId())
+    			.functionIdEq(queryVO.getFunctionId()).builderQueryWrapper();
+    	List<SaasRoleMenu> list = this.saasRoleMenuService.list(queryWrapper);
+    	if (CollectionUtil.isEmpty(list)) {
+			return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+        return ResponseResultUtil.successResult(list, (long)list.size());
+    }
+
+    /**
+     * 新增
+     */
+	@ApiOperation(value = "保存")
+	@RequestMapping(value = "createSaasRoleMenu")
+    public ResponseResult createSaasRoleMenu(@RequestBody @Validated SaasRoleMenuCreateVO createVO) {
+		SaasRoleMenu saasRoleMenu = new SaasRoleMenu();
+		BeanUtils.copyProperties(createVO, saasRoleMenu);
+        boolean result = this.saasRoleMenuService.save(saasRoleMenu);
+        return result ? ResponseResultUtil.successResult("保存成功") : ResponseResultUtil.errorResult("保存失败");
+    }
+	
+    /**
+     * 先删后新增,仅删除此账号角色下的所有菜单功能点的关联关系,并重新新增
+     */
+	@ApiOperation(value = "删除新增")
+	@RequestMapping(value = "resetSaasRoleMenu")
+    public ResponseResult resetSaasRoleMenu(@RequestBody @Validated SaasRoleMenuBatchVO batchVO) {
+		boolean result = this.saasRoleMenuHandler.resetSaasRoleMenu(batchVO.getGroupCode(), batchVO.getRoleId(), batchVO.getAuths());
+        return result ? ResponseResultUtil.successResult("重置成功") : ResponseResultUtil.errorResult("重置失败");
+    }
+    
+    /**
+     * 物理删除
+     */
+    @ApiOperation(value = "删除")
+    @RequestMapping(value = "deleteSaasRoleMenu")
+    public ResponseResult deleteSaasRoleMenu(@RequestBody @Validated SaasRoleMenuQueryVO deleteVO) {
+    	LambdaQueryWrapper<SaasRoleMenu> queryWrapper = new SaasRoleMenu.Builder().createQueryWrapper()
+    			.groupCodeEq(deleteVO.getGroupCode()).roleIdEq(deleteVO.getRoleId()).menuIdEq(deleteVO.getMenuId())
+    			.functionIdEq(deleteVO.getFunctionId()).builderQueryWrapper();
+        boolean result = this.saasRoleMenuService.remove(queryWrapper);
+        return result ? ResponseResultUtil.successResult("删除成功") : ResponseResultUtil.errorResult("删除失败");
+    }
+    
+}

+ 135 - 0
saas-account/src/main/java/com/persagy/person/controller/UpgradeController.java

@@ -0,0 +1,135 @@
+package com.persagy.person.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.esotericsoftware.minlog.Log;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.pojo.dto.SaasAccount;
+import com.persagy.person.pojo.dto.SaasAccountProject;
+import com.persagy.person.pojo.dto.SaasArea;
+import com.persagy.person.pojo.dto.SaasProject;
+import com.persagy.person.pojo.vo.BaseUserVO;
+import com.persagy.person.service.ISaasAccountProjectService;
+import com.persagy.person.service.ISaasAccountService;
+import com.persagy.person.service.ISaasAreaService;
+import com.persagy.person.service.ISaasProjectService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 此类,用做每次迭代升级时,无法通过sql兼容老数据,所需定义的接口信息
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年4月13日:	下午5:46:44
+ */
+@Api(tags = "迭代-升级接口管理")
+@RestController
+@RequestMapping(value = "/upgrade", method = RequestMethod.POST)
+public class UpgradeController {
+	
+    @Autowired
+    private ISaasAreaService saasAreaService;
+    
+    @Autowired
+    private ISaasAccountService saasAccountService;
+    
+    @Autowired
+    private ISaasProjectService saasProjectService;
+    
+	@Autowired
+	private RedisTemplate<String, Object> redisTemplate;
+	
+    @Autowired
+    private ISaasAccountProjectService saasAccountProjectService;
+	
+    /**
+     * 20210413号迭代升级,新增区域权限表,兼容老数据接口,本接口需在部署的时候,手动调用一次,必须返回成功,才算完成
+     * 为防止多次调用,这里采用 REPLACE INTO
+     */
+    @ApiOperation(value = "新增区域权限,兼容老数据接口")
+    @RequestMapping(value = "updateAccountAreaAuth")
+    public ResponseResult updateAccountAreaAuth(@RequestBody @Validated BaseUserVO userVO) {
+    	List<SaasAccountProject> data = new ArrayList<SaasAccountProject>();
+    	// 查询出所有的账号信息,包含停用的
+    	List<SaasAccount> accounts = this.saasAccountService.list();
+    	// 查询出以被分配的项目权限信息
+    	List<SaasAccountProject> accountProject = this.saasAccountProjectService.list();
+    	if (CollectionUtil.isEmpty(accountProject)) {
+    		// 获取所有区域信息
+    		List<SaasArea> areas = this.saasAreaService.list();
+    		// 形成,账号、集团、区域关联关系
+    		for (SaasAccount account : accounts) {
+				for (SaasArea area : areas) {
+					SaasAccountProject saasAccountArea = new SaasAccountProject();
+            		saasAccountArea.setAccountId(account.getId());
+            		saasAccountArea.setGroupCode(account.getGroupCode());
+            		saasAccountArea.setAreaId(area.getId());
+            		data.add(saasAccountArea);
+				}
+			}
+    		this.saasAccountProjectService.replaceAccountProject(data);
+    		return ResponseResultUtil.successResult();
+		}
+    	// 获取不存在项目的,空集合
+    	
+    	// accountProject 不为空,更新对应记录的areaId
+    	for (SaasAccountProject project : accountProject) {
+    		String areaId = null;
+    		// 更新数据
+			LambdaUpdateWrapper<SaasAccountProject> wrapper = new SaasAccountProject.Builder().createUpdateWrapper().accountIdEq(project.getAccountId())
+					.groupCodeEq(project.getGroupCode()).projectIdEq(project.getProjectId()).builderUpdateWrapper();
+    		if (StringUtil.isBlank(project.getProjectId())) {
+    			LambdaQueryWrapper<SaasArea> queryWrapper = new SaasArea.Builder().createQueryWrapper().groupCodeEq(project.getGroupCode()).areaCodeEq(SaasCommonConstant.STR_STATUS_MINUS_1).builderQueryWrapper();
+				SaasArea saasArea = this.saasAreaService.getOne(queryWrapper);
+				areaId = saasArea.getId();
+				wrapper.apply("(PROJECT_ID IS NULL OR TRIM(PROJECT_ID) = '')");
+			} else {
+				LambdaQueryWrapper<SaasProject> queryWrapper = new SaasProject.Builder().createQueryWrapper().groupCodeEq(project.getGroupCode()).projectIdEq(project.getProjectId()).builderQueryWrapper();
+    			SaasProject saasProject = this.saasProjectService.getOne(queryWrapper);
+    			if (saasProject == null) {
+					Log.error("项目信息不存在" + project.getProjectId());
+					continue;
+				}
+    			areaId = saasProject.getAreaId();
+    			wrapper.apply("PROJECT_ID IS NOT NULL AND TRIM(PROJECT_ID) != ''");
+			}
+    		wrapper.set(SaasAccountProject::getAreaId, areaId);
+			this.saasAccountProjectService.update(wrapper);
+    	}
+        return ResponseResultUtil.successResult();
+    }
+    
+    /**
+     * 20210413号迭代升级,清空redis缓存
+     * 为防止多次调用,这里采用 REPLACE INTO
+     */
+    @ApiOperation(value = "新增区域权限表,兼容老数据接口")
+    @RequestMapping(value = "clearRedisCache")
+    public ResponseResult clearRedisCache(@RequestBody @Validated BaseUserVO userVO) {
+    	// 查询出所有的账号信息,包含停用的
+    	List<SaasAccount> accounts = this.saasAccountService.list();
+    	for (SaasAccount saasAccount : accounts) {
+    		this.redisTemplate.delete(saasAccount.getId());
+		}
+        return ResponseResultUtil.successResult();
+    }
+	
+}

+ 169 - 0
saas-account/src/main/java/com/persagy/person/manage/SaasAccountHandler.java

@@ -0,0 +1,169 @@
+package com.persagy.person.manage;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.common.model.BaseGroupModel;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.mq.CommonTopicProducer;
+import com.persagy.person.pojo.dto.SaasAccount;
+import com.persagy.person.pojo.vo.auth.SaasAccountRoleVO;
+import com.persagy.person.service.ISaasAccountProjectService;
+import com.persagy.person.service.ISaasAccountRoleService;
+import com.persagy.person.service.ISaasAccountService;
+import com.persagy.security.util.BouncycastleCipher;
+
+import cn.hutool.core.collection.CollectionUtil;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月16日:	上午10:31:06
+ */
+@Component
+public class SaasAccountHandler {
+
+    @Autowired
+    private BouncycastleCipher bouncycastleCipher;
+    
+    @Autowired
+    private ISaasAccountService saasAccountService;
+    
+	@Autowired
+	private CommonTopicProducer commonTopicProducer;
+    
+	@Autowired
+    private ISaasAccountRoleService saasAccountRoleService;
+	
+    @Autowired
+    private ISaasAccountProjectService saasAccountProjectService;
+	
+	/**
+	 * 账号新增,新增业务集团超管账号的时候,发送mq消息,且关联默认角色
+	 * 
+	 * @param saasAccount
+	 * @param casType
+	 * @param roles
+	 * @return
+	 */
+	@Transactional
+	public boolean createSaasAccount(SaasAccount saasAccount, String casType, List<SaasAccountRoleVO> roles) {
+		boolean result = this.saasAccountService.save(saasAccount);
+		// 新增成功,且是业务系统账号的超管,同步更新权限数据
+		if (result && SaasCommonConstant.STR_STATUS_1.equals(saasAccount.getAccountBelong())
+				&& SaasCommonConstant.STR_STATUS_1.equals(saasAccount.getAccountType())
+				&& StringUtil.isNotBlank(saasAccount.getGroupCode())) {
+			this.addAccountCasUpdateData(saasAccount.getId(), saasAccount.getGroupCode(), saasAccount);
+		}
+		// 判断是否需要添加账号-角色关联关系
+		if (result && CollectionUtil.isNotEmpty(roles)) {
+			this.saasAccountRoleService.resetSaasAccountRole(saasAccount.getGroupCode(), saasAccount.getId(), casType, roles);
+		}
+		return result;
+	}
+	
+	/**
+	 * 更新账号信息
+	 * 
+	 * @param saasAccount
+	 * @param casType
+	 * @param roles
+	 * @return
+	 */
+	@Transactional
+	public boolean updateSaasAccount(SaasAccount saasAccount, String casType, List<SaasAccountRoleVO> roles) {
+		LambdaUpdateWrapper<SaasAccount> updateWrapper = new SaasAccount.Builder().createUpdateWrapper()
+				.idEq(saasAccount.getId()).groupCodeEq(saasAccount.getGroupCode()).builderUpdateWrapper();
+		boolean exists = this.saasAccountService.update(saasAccount, updateWrapper);
+		if (exists) {
+			// 如果更新成功,且是停用的时候,移除token
+			if (SaasCommonConstant.STATUS_0 == saasAccount.getValid()) {
+				this.bouncycastleCipher.remove(saasAccount.getId());
+			}
+			// 只有集团编码不为空时,才会发送mq消息
+			if (StringUtil.isNotBlank(saasAccount.getGroupCode())) {
+				this.commonTopicProducer.sendAccountInfo(saasAccount, SaasCommonConstant.UPDATE_TYPE);
+			}
+			// 判断是否需要添加账号-角色关联关系
+			if (CollectionUtil.isNotEmpty(roles)) {
+				this.saasAccountRoleService.resetSaasAccountRole(saasAccount.getGroupCode(), saasAccount.getId(), casType, roles);
+			}
+		}
+		return exists;
+	}
+	
+    /**
+     * 删除账号信息,账号有恢复操作,这里不级联删除
+     * 
+     * @param deleteModel
+     * @return
+     */
+	@Transactional
+	public boolean deleteSaasAccount(BaseGroupModel deleteModel) {
+		// 逻辑删除
+    	LambdaUpdateWrapper<SaasAccount> updateWrapper = new SaasAccount.Builder().createUpdateWrapper()
+				.idEq(deleteModel.getAccountId()).groupCodeEq(deleteModel.getGroupCode())
+				.validEq(SaasCommonConstant.STATUS_1).builderUpdateWrapper();
+    	updateWrapper.set(SaasAccount::getUpdateUser, deleteModel.getAccountId());
+    	updateWrapper.set(SaasAccount::getValid, SaasCommonConstant.STATUS_0);
+    	boolean result = this.saasAccountService.update(updateWrapper);
+    	/*if (result) {
+    		// 删除本方账号角色菜单关联数据
+    		LambdaQueryWrapper<SaasAccountRole> queryWrapper = new SaasAccountRole.Builder().createQueryWrapper()
+    				.accountIdEq(deleteModel.getAccountId()).groupCodeEq(deleteModel.getGroupCode()).builderQueryWrapper();
+    		this.saasAccountRoleService.remove(queryWrapper);
+    	}*/
+    	return result;
+	}
+
+	/**
+	 * 集团关联业务超管账号
+	 * 
+	 * @param model
+	 * @return
+	 */
+	@Transactional
+	public boolean addSaasAccountGroup(BaseGroupModel model) {
+		LambdaUpdateWrapper<SaasAccount> updateWrapper = new SaasAccount.Builder().createUpdateWrapper().idEq(model.getAccountId())
+				.accountBelongEq(SaasCommonConstant.STR_STATUS_1).accountTypeEq(SaasCommonConstant.STR_STATUS_1).builderUpdateWrapper();
+    	updateWrapper.set(SaasAccount::getUpdateUser, model.getAccountId());
+    	updateWrapper.set(SaasAccount::getGroupCode, model.getGroupCode());
+    	boolean result = this.saasAccountService.update(updateWrapper);
+    	if (result) {
+    		this.addAccountCasUpdateData(model.getAccountId(), model.getGroupCode(), null);
+		}
+		return result;
+	}
+	
+	/**
+	 * 添加账号与集团的关联关系时,需要同步更新的数据
+	 * @param accountId
+	 * @param groupCode
+	 */
+	private void addAccountCasUpdateData(String accountId, String groupCode, SaasAccount saasAccount) {
+		// 插入,默认的账号与业务超管角色关联关系
+		boolean result = this.saasAccountRoleService.addDeafultAccountRole(accountId, groupCode);
+		if (!result) {
+			throw new BusinessException("账号与默认角色关联失败");
+		}
+		// 插入账号、集团、区域信息
+		result = this.saasAccountProjectService.addDefaultAccountArea(accountId, groupCode);
+		if (!result) {
+			throw new BusinessException("账号默认的未分区权限添加失败");
+		}
+		// 发送mq消息,且成功关联了,才发送消息
+		if (saasAccount == null) {
+			saasAccount = this.saasAccountService.getOne(accountId, groupCode, null);
+		}
+		this.commonTopicProducer.sendAccountInfo(saasAccount, SaasCommonConstant.CREATE_TYPE);
+	}
+	
+}

+ 370 - 0
saas-account/src/main/java/com/persagy/person/manage/SaasAreaProjectHandler.java

@@ -0,0 +1,370 @@
+package com.persagy.person.manage;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.person.pojo.dto.SaasAccountProject;
+import com.persagy.person.pojo.dto.SaasArea;
+import com.persagy.person.pojo.dto.SaasGroup;
+import com.persagy.person.pojo.dto.SaasProject;
+import com.persagy.person.pojo.vo.area.SaasAreaQueryVO;
+import com.persagy.person.pojo.vo.project.SaasProjectQueryVO;
+import com.persagy.person.service.ISaasAccountProjectService;
+import com.persagy.person.service.ISaasAreaService;
+import com.persagy.person.service.ISaasProjectService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.BooleanUtil;
+
+/**
+ * 区域项目信息管理
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Component
+public class SaasAreaProjectHandler {
+
+    @Autowired
+    private ISaasAreaService saasAreaService;
+    
+    @Autowired
+    private ISaasProjectService saasProjectService;
+	
+    @Autowired
+    private SaasGroupProjectHandler saasGroupProjectHandler;
+    
+    @Autowired
+    private ISaasAccountProjectService saasAccountProjectService;
+    
+    /**
+     * 查询区域项目树,结构:集团->区域->项目,此方法不做数据权限的控制
+     * @param queryVO
+     * @param saasGroup 
+     */
+	public void queryAreaProjectTree(SaasGroup saasGroup) {
+		List<SaasArea> topList = this.getTopAreaList(saasGroup.getGroupCode());
+		saasGroup.setAreas(topList);
+    	this.querySaasAreaTree(topList, true);
+	}
+	
+	/**
+	 * 获取集团下,顶层区域集合
+	 * 
+	 * @param groupCode
+	 * @return
+	 */
+	public List<SaasArea> getTopAreaList(String groupCode) {
+		LambdaQueryWrapper<SaasArea> queryWrapper = new SaasArea.Builder().createQueryWrapper().groupCodeEq(groupCode).builderQueryWrapper();
+    	queryWrapper.last("AND (PARENT_ID IS NULL OR TRIM(PARENT_ID) = '')");
+    	List<SaasArea> topList = this.saasAreaService.list(queryWrapper);
+    	return CollectionUtil.isEmpty(topList) ? Lists.newArrayList() : topList;
+	}
+	
+    /**
+     * 查询区域项目树
+     * 
+     * @param topList
+     * @param groupCode
+     * @param isCas 是否级联查询出项目信息
+     */
+	public void querySaasAreaTree(List<SaasArea> topList, boolean isCas) {
+		for (SaasArea saasArea : topList) {
+			List<SaasArea> nextList = null;
+			if (isCas && SaasCommonConstant.STR_STATUS_1.equals(saasArea.getAreaType())) {
+				// 级联查询出项目信息
+				LambdaQueryWrapper<SaasProject> projectWrapper = new SaasProject.Builder().createQueryWrapper().areaIdEq(saasArea.getId()).groupCodeEq(saasArea.getGroupCode()).builderQueryWrapper();
+				List<SaasProject> list = this.saasProjectService.list(projectWrapper);
+				list = CollectionUtil.isEmpty(list) ? Lists.newArrayList() : list;
+				saasArea.setProjects(list);
+			} else {
+				LambdaQueryWrapper<SaasArea> queryWrapper = new SaasArea.Builder().createQueryWrapper().groupCodeEq(saasArea.getGroupCode()).parentIdEq(saasArea.getId()).builderQueryWrapper();
+		    	nextList = this.saasAreaService.list(queryWrapper);
+			}
+	    	if (CollectionUtil.isEmpty(nextList)) {
+	    		nextList = Lists.newArrayList();
+			}
+	    	saasArea.setChildrens(nextList);
+	    	this.querySaasAreaTree(nextList, isCas);
+		}
+	}
+    
+	/**
+	 * 区域项目树查询,根据条件做数据权限的控制,剔除不存在项目的区域信息
+	 * 
+	 * @param queryVO 条件
+	 * @param saasGroup 集团信息,不可为空
+	 * @param areaList 区域信息
+	 */
+	public SaasGroup queryAllowAreaProjectTree(SaasProjectQueryVO queryVO, SaasGroup saasGroup, List<SaasArea> areaList) {
+    	// 查询可见范围内的项目信息
+    	SaasProject saasProject = new SaasProject();
+		BeanUtils.copyProperties(queryVO, saasProject);
+    	Page<SaasProject> projectList = this.saasGroupProjectHandler.querySaasProjectList(saasProject, null, null);
+    	List<SaasProject> records = projectList.getRecords();
+    	if (CollectionUtil.isEmpty(records)) {
+    		return saasGroup;		//项目信息为空时,直接返回
+		}
+    	// 首先遍历项目信息,形成临时map
+    	Map<String, List<SaasProject>> tempPro = new HashMap<String, List<SaasProject>>();
+    	for (SaasProject project : records) {
+    		if (tempPro.containsKey(project.getAreaId())) {
+    			tempPro.get(project.getAreaId()).add(project);
+			} else {
+				tempPro.put(project.getAreaId(), Lists.newArrayList(project));
+			}
+		}
+    	// 组合成结果树
+    	boolean showEmptyArea = BooleanUtil.isTrue(queryVO.getShowEmptyArea());
+    	this.queryAllowAreaProjectTree(areaList, tempPro, !showEmptyArea);
+    	return saasGroup;
+	}
+	
+	/**
+	 * 区域项目树封装,剔除不存在项目的区域信息
+	 * 
+	 * @param areaList 区域集合
+	 * @param tempPro 临时项目信息集合 key-areaId,value-projectInfo
+	 * @param delEmptyArea 是否剔除空区域
+	 */
+	private void queryAllowAreaProjectTree(List<SaasArea> areaList, Map<String, List<SaasProject>> tempPro, boolean delEmptyArea) {
+		for (int i = areaList.size() - 1; i >= 0; i--) {
+			SaasArea saasArea = areaList.get(i);
+			//底层区域
+			if (SaasCommonConstant.STR_STATUS_1.equals(saasArea.getAreaType())) {
+				if (tempPro.containsKey(saasArea.getId())) {
+					saasArea.setProjects(tempPro.get(saasArea.getId()));
+				} else if (delEmptyArea) {
+					areaList.remove(i);		//移除
+				}
+			} else if (CollectionUtil.isEmpty(saasArea.getChildrens()) && delEmptyArea) {
+				areaList.remove(i);			//移除
+			} else {
+				this.queryAllowAreaProjectTree(saasArea.getChildrens(), tempPro, delEmptyArea);
+				// 最后还需判断一次,递归回路删除上级区域信息
+				if (delEmptyArea && CollectionUtil.isEmpty(saasArea.getChildrens()) && CollectionUtil.isEmpty(saasArea.getProjects())) {
+					areaList.remove(i);		//移除
+				}
+			}
+		}
+	}
+
+	/**
+     * 查询区域平铺列表
+     * @param queryVO
+     * @param isAdmin 是否需要查询出对应集团与区域下所有的项目数
+     */
+	public List<SaasArea> querySaasAreaList(SaasAreaQueryVO queryVO, boolean isAdmin) {
+		String groupCode = queryVO.getGroupCode();
+		String accountId = queryVO.getAccountId();
+		
+		LambdaQueryWrapper<SaasArea> queryWrapper = new SaasArea.Builder().createQueryWrapper().idEq(queryVO.getId())
+    			.groupCodeEq(groupCode).areaCodeEq(queryVO.getAreaCode()).areaNameLike(queryVO.getAreaName())
+    			.areaTypeEq(queryVO.getAreaType()).updateUserEq(queryVO.getUpdateUser())
+    			.parentIdEq(queryVO.getParentId()).builderQueryWrapper();
+		List<SaasArea> areas = this.saasAreaService.list(queryWrapper);
+		if (CollectionUtil.isEmpty(areas)) {
+			return Lists.newArrayList();
+		}
+		if (queryVO.isTotal()) {	// 统计出项目数量
+			for (SaasArea saasArea : areas) {
+				if (SaasCommonConstant.STR_STATUS_1.equals(saasArea.getAreaType())) {
+					int count = 0;
+					if (isAdmin) {
+						LambdaQueryWrapper<SaasProject> projectWrapper = new SaasProject.Builder().createQueryWrapper().areaIdEq(saasArea.getId()).groupCodeEq(groupCode).builderQueryWrapper();
+						count = this.saasProjectService.count(projectWrapper);
+					} else {
+						// 权限过滤掉项目
+						count = this.saasProjectService.countAllowProjectNum(groupCode, accountId, saasArea.getId());
+					}
+					saasArea.setProjectNum(count);
+					continue;
+				}
+				// 非底层区域,递归查询
+				queryWrapper = new SaasArea.Builder().createQueryWrapper().groupCodeEq(groupCode).parentIdEq(saasArea.getId()).builderQueryWrapper();
+		    	List<SaasArea> nextList = this.saasAreaService.list(queryWrapper);
+		    	if (CollectionUtil.isEmpty(nextList)) {
+		    		saasArea.setProjectNum(0);
+		    		continue;
+				}
+		    	saasArea.setProjectNum(0);		//初始化数量
+		    	this.queryAreaProjectNum(nextList, groupCode, saasArea);
+			}
+		}
+    	return areas;
+	}
+	
+	/**
+     * 底层区域平铺列表查询(权限过滤)
+     * @param areas
+     * @param isAdmin 是否需要查询出对应集团与区域下所有的项目数
+     */
+	public List<SaasArea> totalAreaProjectNum(List<SaasArea> areas, String accountId, boolean isAdmin) {
+		for (SaasArea saasArea : areas) {
+			if (SaasCommonConstant.STR_STATUS_1.equals(saasArea.getAreaType())) {
+				int count = 0;
+				if (isAdmin) {
+					LambdaQueryWrapper<SaasProject> projectWrapper = new SaasProject.Builder().createQueryWrapper().areaIdEq(saasArea.getId()).groupCodeEq(saasArea.getGroupCode()).builderQueryWrapper();
+					count = this.saasProjectService.count(projectWrapper);
+				} else {
+					// 权限过滤掉项目
+					count = this.saasProjectService.countAllowProjectNum(saasArea.getGroupCode(), accountId, saasArea.getId());
+				}
+				saasArea.setProjectNum(count);
+			}
+		}
+    	return areas;
+	}
+	
+	/**
+	 * 查询出当前区域集合,所包含的项目总数
+	 * @param areas
+	 * @param groupCode
+	 * @param num
+	 */
+	private void queryAreaProjectNum(List<SaasArea> areas, String groupCode, SaasArea saasArea) {
+		for (SaasArea area : areas) {
+			List<SaasArea> nextList = null;
+			if (SaasCommonConstant.STR_STATUS_1.equals(area.getAreaType())) {
+				// 级联统计出项目信息
+				LambdaQueryWrapper<SaasProject> projectWrapper = new SaasProject.Builder().createQueryWrapper().areaIdEq(area.getId()).groupCodeEq(groupCode).builderQueryWrapper();
+				int count = this.saasProjectService.count(projectWrapper);
+				saasArea.setProjectNum(saasArea.getProjectNum() + count);
+			} else {
+				LambdaQueryWrapper<SaasArea> queryWrapper = new SaasArea.Builder().createQueryWrapper().groupCodeEq(groupCode).parentIdEq(area.getId()).builderQueryWrapper();
+		    	nextList = this.saasAreaService.list(queryWrapper);
+			}
+	    	if (CollectionUtil.isEmpty(nextList)) {
+	    		nextList = Lists.newArrayList();
+			}
+	    	this.queryAreaProjectNum(nextList, groupCode, saasArea);
+		}
+	}
+
+	/**
+	 * 查询被允许访问的区域树,账号类型为其他
+	 * 
+	 * @param topList 顶级区域集合
+	 * @param accountId
+	 * @param groupCode
+	 */
+	public List<SaasArea> queryAllowAreaTree(List<SaasArea> topList, String accountId, String groupCode) {
+		// 获取权限表中区域信息
+		Set<String> areaIds = this.saasAccountProjectService.queryAccountAreaIds(accountId, groupCode);
+		if (CollectionUtil.isEmpty(areaIds)) {
+			return Lists.newArrayList();
+		}
+		this.queryAllowAreaTree(topList, areaIds);
+		return topList;
+	}
+
+	/**
+	 * 区域权限树封装,剔除不被允许访问的区域
+	 * 
+	 * @param areaList 区域集合
+	 * @param tempPro 临时项目信息集合 key-areaId,value-projectInfo
+	 * @param delEmptyArea 是否剔除空区域
+	 */
+	private void queryAllowAreaTree(List<SaasArea> areaList, Set<String> areaIds) {
+		for (int i = areaList.size() - 1; i >= 0; i--) {
+			SaasArea saasArea = areaList.get(i);
+			//底层区域
+			if (SaasCommonConstant.STR_STATUS_1.equals(saasArea.getAreaType())) {
+				if (!areaIds.contains(saasArea.getId())) {
+					areaList.remove(i);		//移除
+				}
+			} else {
+				this.queryAllowAreaTree(saasArea.getChildrens(), areaIds);
+				// 最后还需判断一次,递归回路删除上级区域信息
+				if (CollectionUtil.isEmpty(saasArea.getChildrens()) && !areaIds.contains(saasArea.getId())) {
+					areaList.remove(i);		//移除
+				}
+			}
+		}
+	}
+
+	/**
+	 * 添加区域信息时,判断此账号是否需要添加一条权限信息
+	 * 
+	 * @param saasArea
+	 */
+	@Transactional
+	public boolean createSaasArea(SaasArea saasArea, String accountId, String accountType) {
+		boolean result = this.saasAreaService.save(saasArea);
+		if (result && SaasCommonConstant.STR_STATUS_2.equals(accountType)) {
+			// 其他账号类型时,添加一条账号、集团、分区的权限信息
+			SaasAccountProject saasAccountProject = new SaasAccountProject();
+			saasAccountProject.setAccountId(accountId);
+			saasAccountProject.setGroupCode(saasArea.getGroupCode());
+			saasAccountProject.setAreaId(saasArea.getId());
+			result = this.saasAccountProjectService.save(saasAccountProject);
+			if (!result) {
+				throw new BusinessException("此账号,添加此新分区权限时,添加失败");
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * 删除分区信息
+	 * 
+	 * @param groupCode
+	 * @param areaId
+	 * @param accountType
+	 * @return
+	 */
+	@Transactional
+	public boolean deleteSaasArea(String groupCode, String areaId, String accountType) {
+		boolean result = this.saasAreaService.removeById(areaId);
+		if (result && SaasCommonConstant.STR_STATUS_2.equals(accountType)) {
+			// 其他账号类型时,删除所有账号的此集团、此分区的权限信息,这里不要进行返回值判断
+			LambdaQueryWrapper<SaasAccountProject> queryWrapper = new SaasAccountProject.Builder().createQueryWrapper().groupCodeEq(groupCode).areaIdEq(areaId).builderQueryWrapper();
+			this.saasAccountProjectService.remove(queryWrapper);
+		}
+		return result;
+	}
+
+	/**
+	 * 验证此区域是否允许被删除
+	 * 
+	 * @param parentId
+	 * @param groupCode
+	 * @param result 调用时传true
+	 * @return 没有下级默认允许-true,
+	 */
+	/*public boolean validAreaProjectExist(List<SaasArea> saasAreas, String groupCode) {
+		if (CollectionUtil.isEmpty(saasAreas)) {
+			return true;
+		}
+    	for (SaasArea area : saasAreas) {
+    		// 如果是底层区域,判断,旗下是否存在项目信息,存在不允许删除
+        	if (SaasCommonConstant.STR_STATUS_1.equals(area.getAreaType())) {
+        		LambdaQueryWrapper<SaasProject> projectWrapper = new SaasProject.Builder().createQueryWrapper()
+        				.groupCodeEq(groupCode).areaIdEq(area.getId()).last("limit 0, 1").builderQueryWrapper();
+    			SaasProject project = this.saasProjectService.getOne(projectWrapper);
+    			if (project != null) {
+    				return false;
+    			}
+    		} 
+        	// 继续递归
+        	LambdaQueryWrapper<SaasArea> queryWrapper = new SaasArea.Builder().createQueryWrapper().parentIdEq(area.getId()).groupCodeEq(groupCode).builderQueryWrapper();
+        	List<SaasArea> nextAreas = this.saasAreaService.list(queryWrapper);
+        	this.validAreaProjectExist(nextAreas, groupCode);
+		}
+	}*/
+
+}

+ 197 - 0
saas-account/src/main/java/com/persagy/person/manage/SaasAuthHandler.java

@@ -0,0 +1,197 @@
+package com.persagy.person.manage;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.pojo.dto.SaasAccount;
+import com.persagy.person.pojo.dto.SaasArea;
+import com.persagy.person.pojo.dto.SaasGroup;
+import com.persagy.person.service.ISaasAccountService;
+import com.persagy.person.service.ISaasGroupService;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月18日:	上午10:20:22
+ */
+@Component
+public class SaasAuthHandler {
+	
+    @Autowired
+    private ISaasGroupService saasGroupService;
+
+    @Autowired
+    private ISaasAccountService saasAccountService;
+    
+    @Autowired
+    private SaasAreaProjectHandler saasAreaProjectHandler;
+    
+    /**
+     * 验证此账号的集团项目权限
+     * 
+     * @param accountId
+     * @param groupCode
+     * @return 
+     * 	权限鉴定通过时: 
+     * 	若有返回集团编码,则此返回值必须作为代码向下执行的sql条件;
+     * 	若有返回accountType,需进行 SaasCommonConstant.STR_STATUS_2.equals(accountType) 账号类型的判断
+     */
+    public Map<String, String> validGroupProjectAuth(String accountId, String groupCode) {
+    	// 获取此账号对应的集团权限
+    	SaasAccount account = this.saasAccountService.getOne(accountId, null, null);
+    	if (account == null) {
+    		throw new BusinessException("账号信息为空");
+		}
+    	// 添加数据访问控制,账号类型,0-所有集团项目,1-单集团所有项目,2-其他
+    	String accountType = account.getAccountType();
+		// 1时,判断是否有权限
+    	Map<String, String> result = new HashMap<String, String>(2);
+		if (SaasCommonConstant.STR_STATUS_1.equals(accountType)) {
+			String allowGroupCode = account.getGroupCode();
+			if (StringUtil.isNotBlank(groupCode) && !groupCode.equals(allowGroupCode)) {
+				throw new BusinessException("账号无该集团的访问权限");
+			}
+			result.put(SaasCommonConstant.GROUP_CODE, allowGroupCode);
+		}
+		result.put(SaasCommonConstant.ACCOUNT_TYPE, accountType);
+		return result;
+    }
+    
+    /**
+     * 返回允许此账号访问的集团信息
+     * 
+     * @param accountId
+     * @param groupCode
+     * @return 允许此账号访问的集团信息
+     */
+    public List<SaasGroup> getAllowGroupList(String accountId, String groupCode) {
+    	// 获取此账号对应的集团权限
+    	SaasAccount account = this.saasAccountService.getOne(accountId, null, null);
+    	if (account == null) {
+    		throw new BusinessException("账号信息为空");
+		}
+    	// 添加数据访问控制,账号类型,0-所有集团项目,1-单集团所有项目,2-其他
+    	String accountType = account.getAccountType();
+		// 1时,判断是否有权限
+		if (SaasCommonConstant.STR_STATUS_1.equals(accountType)) {
+			String allowGroupCode = account.getGroupCode();
+			if (StringUtil.isNotBlank(groupCode) && !groupCode.equals(allowGroupCode)) {
+				throw new BusinessException("账号无该集团的访问权限");
+			}
+			groupCode = allowGroupCode;
+		}
+		return this.getAllowGroupList(accountId, groupCode, accountType);
+    }
+    
+    /**
+     * 返回允许此账号访问的集团信息
+     * 
+     * @param accountId
+     * @param groupCode
+     * @param accountType
+     * @return 允许此账号访问的集团信息
+     */
+    public List<SaasGroup> getAllowGroupList(String accountId, String groupCode, String accountType) {
+    	List<SaasGroup> groups = null;
+    	if (SaasCommonConstant.STR_STATUS_2.equals(accountType)) {
+			SaasGroup saasGroup = new SaasGroup();
+			saasGroup.setGroupCode(groupCode);
+			saasGroup.setValid(SaasCommonConstant.STATUS_1);
+			groups = this.saasGroupService.queryAllowGroupInfo(saasGroup, accountId);
+		} else {
+			LambdaQueryWrapper<SaasGroup> queryWrapper = new SaasGroup.Builder().createQueryWrapper().validEq(SaasCommonConstant.STATUS_1).builderQueryWrapper();
+    		groups = this.saasGroupService.list(queryWrapper);
+		}
+		return groups == null ? Lists.newArrayList() : groups;
+    }
+    
+    /**
+     * 返回被允许访问的区域树
+     * 
+     * @param accountId
+     * @param groupCode
+     * @return 允许此账号访问的集团信息
+     */
+    public List<SaasArea> getAllowAreaList(String accountId, String groupCode) {
+    	// 获取此账号对应的集团权限
+    	SaasAccount account = this.saasAccountService.getOne(accountId, null, null);
+    	if (account == null) {
+    		throw new BusinessException("账号信息为空");
+		}
+    	// 添加数据访问控制,账号类型,0-所有集团项目,1-单集团所有项目,2-其他
+    	String accountType = account.getAccountType();
+		// 1时,判断是否有权限
+		if (SaasCommonConstant.STR_STATUS_1.equals(accountType)) {
+			String allowGroupCode = account.getGroupCode();
+			if (StringUtil.isNotBlank(groupCode) && !groupCode.equals(allowGroupCode)) {
+				throw new BusinessException("账号无该集团的访问权限");
+			}
+			groupCode = allowGroupCode;
+		}
+		return this.getAllowAreaList(accountId, groupCode, accountType);
+    }
+    
+    /**
+     * 返回被允许访问的区域树
+     * 
+     * @param accountId
+     * @param groupCode
+     * @param accountType
+     * @return 
+     */
+    public List<SaasArea> getAllowAreaList(String accountId, String groupCode, String accountType) {
+    	List<SaasArea> topList = this.saasAreaProjectHandler.getTopAreaList(groupCode);
+		if (SaasCommonConstant.STR_STATUS_2.equals(accountType)) {
+			// 其他类型时,需要根据权限表数据,去匹配区域树
+			this.saasAreaProjectHandler.queryAllowAreaTree(topList, accountId, groupCode);
+		} else {
+	    	this.saasAreaProjectHandler.querySaasAreaTree(topList, false);
+		}
+		return topList;
+    }
+    
+    /**
+     * 验证此账号的菜单权限
+     * 
+     * @param accountId
+     * @param groupCode
+     * @return 
+     * 	权限鉴定通过时: 
+     *  有accountbelong 账号所属字段
+     * 	若有返回集团编码,则此返回值必须作为代码向下执行的sql条件;
+     * 	若有返回accountType,需进行 SaasCommonConstant.STR_STATUS_2.equals(accountType) 账号类型的判断
+     */
+    public Map<String, String> validSaasMenuAuth(String accountId, String groupCode) {
+    	// 获取此账号对应的集团权限
+    	SaasAccount account = this.saasAccountService.getOne(accountId, null, null);
+    	if (account == null) {
+    		throw new BusinessException("账号信息为空");
+		}
+    	// 添加数据访问控制,账号类型,0-所有集团项目,1-单集团所有项目,2-其他
+    	String accountType = account.getAccountType();
+		// 1时,判断是否有权限
+    	Map<String, String> result = new HashMap<String, String>(2);
+		if (SaasCommonConstant.STR_STATUS_1.equals(accountType)) {
+			String allowGroupCode = account.getGroupCode();
+			if (StringUtil.isNotBlank(groupCode) && !groupCode.equals(allowGroupCode)) {
+				throw new BusinessException("账号无该集团的访问权限");
+			}
+			result.put(SaasCommonConstant.GROUP_CODE, allowGroupCode);
+		}
+		result.put(SaasCommonConstant.ACCOUNT_TYPE, accountType);
+		result.put(SaasCommonConstant.ACCOUNT_BELONG, account.getAccountBelong());
+		return result;
+    }
+    
+}

+ 213 - 0
saas-account/src/main/java/com/persagy/person/manage/SaasGroupProjectHandler.java

@@ -0,0 +1,213 @@
+package com.persagy.person.manage;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.mq.CommonTopicProducer;
+import com.persagy.person.pojo.dto.SaasAccount;
+import com.persagy.person.pojo.dto.SaasAccountProject;
+import com.persagy.person.pojo.dto.SaasGroup;
+import com.persagy.person.pojo.dto.SaasProject;
+import com.persagy.person.pojo.vo.group.SaasGroupQueryVO;
+import com.persagy.person.service.ISaasAccountProjectService;
+import com.persagy.person.service.ISaasAccountService;
+import com.persagy.person.service.ISaasAreaService;
+import com.persagy.person.service.ISaasGroupService;
+import com.persagy.person.service.ISaasProjectService;
+import com.persagy.person.service.ISaasRoleService;
+
+import cn.hutool.core.collection.CollectionUtil;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月18日:	上午10:20:22
+ */
+@Component
+public class SaasGroupProjectHandler {
+
+	@Autowired
+	private SaasAuthHandler saasAuthHandler;
+	
+    @Autowired
+    private ISaasAreaService saasAreaService;
+    
+    @Autowired
+    private ISaasRoleService saasRoleService;
+    
+    @Autowired
+    private ISaasGroupService saasGroupService;
+    
+    @Autowired
+    private ISaasProjectService saasProjectService;
+    
+    @Autowired
+    private ISaasAccountService saasAccountService;
+    
+	@Autowired
+	private CommonTopicProducer commonTopicProducer;
+	
+    @Autowired
+    private ISaasAccountProjectService saasAccountProjectService;
+	
+    /**
+     * 查询集团信息
+     * 
+     * @param queryVO
+     */
+	public List<SaasGroup> querySaasGroupList(SaasGroupQueryVO queryVO) {
+		LambdaQueryWrapper<SaasGroup> queryWrapper = new SaasGroup.Builder().createQueryWrapper()
+				.groupCodeEq(queryVO.getGroupCode()).groupNameLike(queryVO.getGroupName())
+				.deployModelEq(queryVO.getDeployModel()).syncStateEq(queryVO.getSyncState())
+				.updateUserEq(queryVO.getUpdateUser()).validEq(queryVO.getValid()).builderQueryWrapper();
+    	return this.saasGroupService.list(queryWrapper);
+	}
+	
+	/**
+	 * 查询集团项目树,默认集团名称、项目名称正序排序
+	 * 
+	 * @param groupCode
+	 * @param isDirect 是否直接查询,true-是,false-走权限表关联查询
+	 * @return
+	 */
+	public List<SaasGroup> queryGroupProjectTree(String accountId, String groupCode, boolean isDirect) {
+		LambdaQueryWrapper<SaasGroup> groupWrapper = new SaasGroup.Builder().createQueryWrapper().groupCodeEq(groupCode).validEq(SaasCommonConstant.STATUS_1).builderQueryWrapper();
+		groupWrapper.orderByAsc(SaasGroup::getGroupName);		//集团名称正序排序
+		List<SaasGroup> groups = this.saasGroupService.list(groupWrapper);
+		if (CollectionUtil.isEmpty(groups)) {
+			return Lists.newArrayList();
+		}
+		// 设置每个集团下的项目集合信息
+		LambdaQueryWrapper<SaasProject> queryWrapper = null;
+		for (SaasGroup saasGroup : groups) {
+			List<SaasProject> list = null;
+			if (isDirect) {
+				queryWrapper = new SaasProject.Builder().createQueryWrapper().groupCodeEq(saasGroup.getGroupCode()).validEq(SaasCommonConstant.STATUS_1).builderQueryWrapper();
+				queryWrapper.orderByAsc(SaasProject::getProjectName);		//项目名称正序排序
+				list = this.saasProjectService.list(queryWrapper);
+			} else {
+				// 表关联查询
+				list = this.saasProjectService.queryAllowGroupProjectList(groupCode, accountId);
+			}
+			if (CollectionUtil.isEmpty(list)) {
+				list = Lists.newArrayList();
+			}
+			saasGroup.setProjects(list);
+		}
+        return groups;
+	}
+	
+	/**
+	 * 创建集团的同时,添加ACCOUNT_PROJECT表中一条对应的权限信息
+	 * @param saasGroup
+	 * @return
+	 */
+    @Transactional
+	public ResponseResult createSaasGroup(SaasGroup saasGroup, String accountId) {
+    	// 获取账号信息
+		SaasAccount account = this.saasAccountService.getOne(accountId, null, null);
+		if (account == null) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "账号信息不存在");
+		}
+		if (SaasCommonConstant.STR_STATUS_1.equals(account.getAccountType())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0301.getCode(), "单集团管理员,不允许添加集团");
+		}
+		boolean result = this.saasGroupService.save(saasGroup);
+		String areaId = null;
+		if (result) {
+			// 生成一条未分区的区域信息
+			areaId = this.saasAreaService.createEmptyAreaInfo(saasGroup.getGroupCode(), saasGroup.getUpdateUser());
+			if (areaId == null) {
+				throw new BusinessException("集团默认分区添加失败");
+			}
+			// 生成一条默认的角色信息及角色,默认菜单的关联关系,这里的菜单先写死
+			this.saasRoleService.createDefaultRole(saasGroup.getGroupCode(), saasGroup.getGroupName(), saasGroup.getUpdateUser());
+		}
+		// 账号类型为其他类型的账号添加集团信息时,需要在ACCOUNT_PROJECT插入一条权限信息
+		if (result && SaasCommonConstant.STR_STATUS_2.equals(account.getAccountType())) {
+			// 插入权限信息
+			SaasAccountProject saasAccountProject = new SaasAccountProject();
+			saasAccountProject.setAccountId(accountId);
+			saasAccountProject.setAreaId(areaId);
+			saasAccountProject.setGroupCode(saasGroup.getGroupCode());
+			result = this.saasAccountProjectService.save(saasAccountProject);
+			if (!result) {
+				throw new BusinessException("集团权限信息添加失败");
+			}
+		}
+		if (result) {
+			this.commonTopicProducer.sendGroupInfo(saasGroup, SaasCommonConstant.CREATE_TYPE);
+			return ResponseResultUtil.successResult("保存成功");
+		}
+		return ResponseResultUtil.errorResult("保存失败");
+	}
+	
+    /**
+     * 查询项目信息
+     * 
+     * @param queryVO
+     * @param startRow
+     * @param size
+     * @return
+     */
+    public Page<SaasProject> querySaasProjectList(SaasProject saasProject, Integer page, Integer size) {
+		// 账号数据可见性的权限鉴定
+		Map<String, String> authMap = this.saasAuthHandler.validGroupProjectAuth(saasProject.getAccountId(), saasProject.getGroupCode());
+		if (StringUtil.isNotBlank(authMap.get(SaasCommonConstant.GROUP_CODE))) {
+			saasProject.setGroupCode(authMap.get(SaasCommonConstant.GROUP_CODE));
+		}
+    	String accountType = authMap.get(SaasCommonConstant.ACCOUNT_TYPE);
+    	Page<SaasProject> projectList = null;
+		if (SaasCommonConstant.STR_STATUS_2.equals(accountType)) {
+			projectList = this.saasProjectService.queryMoreProjectInfo(saasProject, page, size);
+		} else {
+			projectList = this.saasProjectService.querySaasProjectList(saasProject, page, size);
+		}
+		return projectList;
+    }
+
+    /**
+     * 创建项目信息的同时,判断是否需要添加一条权限信息
+     * 
+     * @param saasProject
+     * @param accountId
+     */
+    @Transactional
+	public ResponseResult createSaasProject(SaasProject saasProject, String accountId) {
+    	// 获取账号信息
+		SaasAccount account = this.saasAccountService.getOne(accountId, null, null);
+		if (account == null) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0402.getCode(), "账号信息不存在");
+		}
+		boolean result = this.saasProjectService.save(saasProject);
+		// 账号类型为其他的账号添加集团信息时,需要在ACCOUNT_PROJECT插入一条权限信息
+		if (result && SaasCommonConstant.STR_STATUS_2.equals(account.getAccountType())) {
+			// 插入权限信息
+			SaasAccountProject saasAccountProject = new SaasAccountProject();
+			saasAccountProject.setAccountId(accountId);
+			saasAccountProject.setGroupCode(saasProject.getGroupCode());
+			saasAccountProject.setProjectId(saasProject.getProjectId());
+			result = this.saasAccountProjectService.save(saasAccountProject);
+			if (!result) {
+				throw new BusinessException("项目权限信息添加失败");
+			}
+		}
+		return result ? ResponseResultUtil.successResult("保存成功", saasProject.getId()) : ResponseResultUtil.errorResult("保存失败");
+	}
+
+}

+ 144 - 0
saas-account/src/main/java/com/persagy/person/manage/SaasProjectExcelDataHandler.java

@@ -0,0 +1,144 @@
+package com.persagy.person.manage;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.beans.BeanUtils;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import com.alibaba.excel.exception.ExcelAnalysisException;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseUserModel;
+import com.persagy.common.utils.IdGenerator;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.pojo.dto.SaasArea;
+import com.persagy.person.pojo.dto.SaasProject;
+import com.persagy.person.pojo.vo.project.SaasProjectExcel;
+import com.persagy.person.service.ISaasAreaService;
+import com.persagy.person.service.ISaasProjectService;
+
+import cn.hutool.core.collection.CollectionUtil;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 传感器数据导入, 此类不能被spring管理,要每次读取excel都要new
+ * 
+ * @version v1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2020-11-25 19:52:37
+ */
+@Slf4j
+public class SaasProjectExcelDataHandler extends AnalysisEventListener<SaasProjectExcel> {
+	
+	private BaseUserModel baseVO;
+	
+	private ISaasAreaService saasAreaService;
+	
+	private ISaasProjectService saasProjectService;
+	
+	/**
+	 * 上传的数据
+	 */
+	private List<SaasProject> list = new ArrayList<SaasProject>();
+	
+	private Set<String> validProjectId = new HashSet<String>();
+	private Set<String> validLocalId = new HashSet<String>();
+	private Set<String> validProjectName = new HashSet<String>();
+	
+	public SaasProjectExcelDataHandler() {
+		
+	}
+	
+	public SaasProjectExcelDataHandler(BaseUserModel baseVO, ISaasAreaService saasAreaService, ISaasProjectService saasProjectService) {
+		this.baseVO = baseVO;
+		this.saasAreaService = saasAreaService;
+		this.saasProjectService = saasProjectService;
+	}
+	
+	/**
+	 * 每一条数据解析都会来调用
+	 * 
+	 * @param data one row value {@link AnalysisContext#readRowHolder()}
+	 * @param context
+	 */
+	@Override
+	public void invoke(SaasProjectExcel data, AnalysisContext context) {
+		// 数据不可为空校验
+		int rowIndex = context.readRowHolder().getRowIndex();
+		if (list.size() > 299) {
+			throw new ExcelAnalysisException("导入数据量过大,不允许超过300条!");
+		}
+		if (!StringUtil.isAllNotBlank(data.getGroupCode(), data.getProjectId(), data.getProjectLocalId(), data.getProjectName())) {
+			throw new ExcelAnalysisException("第" + rowIndex + "行数据,红色必填项存在为空的单元格,请检查!");
+		}
+		String projectId = data.getGroupCode() + data.getProjectId();
+		String localId = data.getGroupCode() + data.getProjectLocalId();
+		String projectName = data.getGroupCode() + data.getProjectName();
+		if (validProjectId.contains(projectId)) {
+			throw new ExcelAnalysisException("第" + rowIndex + "行数据,项目ID已存在表中,请检查!");
+		}
+		if (validLocalId.contains(localId)) {
+			throw new ExcelAnalysisException("第" + rowIndex + "行数据,项目本地编码已存在表中,请检查!");
+		}
+		if (validProjectName.contains(projectName)) {
+			throw new ExcelAnalysisException("第" + rowIndex + "行数据,项目名称已存在表中,请检查!");
+		}
+		// 格式转换
+		list.add(this.convertSaasProjectData(data, rowIndex));
+	}
+
+	/**
+	 * 所有数据解析完成了都会来调用,在这里进行数据存储,可确保最后遗留的数据也被存储到数据库
+	 * @param context
+	 */
+	@Override
+	public void doAfterAllAnalysed(AnalysisContext context) {
+		if (CollectionUtil.isNotEmpty(list)) {
+			this.saasProjectService.batchInsertProjectData(list);
+		}
+		log.info("项目数据导入成功,操作者: {}", baseVO.getAccountId());
+	}
+
+	/**
+	 * 转变为能够直接存入数据库的数据形式
+	 * @param data
+	 */
+	private SaasProject convertSaasProjectData(SaasProjectExcel data, int rowIndex) {
+		SaasProject info = new SaasProject();
+		BeanUtils.copyProperties(data, info);
+		Date date = new Date();
+		info.setCreateTime(date);
+		info.setUpdateTime(date);
+		info.setGroupCode(data.getGroupCode());
+		info.setUpdateUser(baseVO.getAccountId());
+		info.setId(IdGenerator.getSnowIdStr(SaasCommonConstant.SAAS_PROJECT_ID_PREFIX));
+		// 数据分割
+		String groupCode = data.getGroupCode().split("_")[0];
+		info.setGroupCode(groupCode);
+		
+		String areaName = data.getAreaId();
+		if (StringUtil.isBlank(areaName)) {
+			info.setAreaId(SaasCommonConstant.STR_STATUS_MINUS_1);
+		} else {
+			// 查询出当前name对应的ID
+			SaasArea areaOne = this.saasAreaService.getAreaOne(null, groupCode, null, areaName);
+			if (areaOne == null) {
+				throw new ExcelAnalysisException("第" + rowIndex + "行数据,项目所属区域不存在,请检查!");
+			}
+			info.setAreaId(areaOne.getId());
+		}
+		
+		// 验证数据的唯一性
+		boolean result = this.saasProjectService.validProjectData(info, false);
+		if (!result) {
+			throw new ExcelAnalysisException("第" + rowIndex + "行数据,数据库中存已存在该条记录,请检查!");
+		}
+		return info;
+	}
+	
+}

+ 170 - 0
saas-account/src/main/java/com/persagy/person/manage/SaasProjectSheetWriteHandler.java

@@ -0,0 +1,170 @@
+package com.persagy.person.manage;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.DataValidation;
+import org.apache.poi.ss.usermodel.DataValidationConstraint;
+import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.Name;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
+
+import com.alibaba.excel.write.handler.SheetWriteHandler;
+import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
+import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.utils.ExcelUtil;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.pojo.dto.SaasArea;
+import com.persagy.person.pojo.dto.SaasGroup;
+import com.persagy.person.pojo.vo.area.SaasAreaQueryVO;
+import com.persagy.person.pojo.vo.group.SaasGroupQueryVO;
+
+import cn.hutool.core.collection.CollectionUtil;
+
+/**
+ * 设置传感器模板文件下拉框选项值
+ * 
+ * @version v1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2020-11-25 19:52:37
+ */
+public class SaasProjectSheetWriteHandler implements SheetWriteHandler {
+
+	private SaasAreaProjectHandler saasAreaProjectHandler;
+	
+	private SaasGroupProjectHandler saasGroupProjectHandler;
+	
+	private static String[] groupArray = null;
+	
+	// key-groupCode+groupName,value-目前是底层区域集合
+	private Map<String, List<String>> areaMap = null;
+	
+	public SaasProjectSheetWriteHandler() {}
+	
+	public SaasProjectSheetWriteHandler(SaasGroupProjectHandler saasGroupProjectHandler, SaasAreaProjectHandler saasAreaProjectHandler) {
+		this.saasAreaProjectHandler = saasAreaProjectHandler;
+		this.saasGroupProjectHandler = saasGroupProjectHandler;
+	}
+	
+	/**
+	 * 再sheet创建之前,填充下拉框的数据
+	 */
+	@Override
+	public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
+		// 1.查询集团项目
+		SaasGroupQueryVO groupVO = new SaasGroupQueryVO();
+		Map<String, String> temp = new HashMap<String, String>();
+		List<SaasGroup> list = this.saasGroupProjectHandler.querySaasGroupList(groupVO);
+		if (CollectionUtil.isNotEmpty(list)) {
+			groupArray = new String[list.size()];
+			for(int i = 0; i < list.size(); i++) {
+				SaasGroup saasGroup = list.get(i);
+				String value = saasGroup.getGroupCode() + "_" + saasGroup.getGroupName();
+				temp.put(saasGroup.getGroupCode(), value);
+				groupArray[i] = value;
+			}
+		} else {
+			groupArray = new String[1];
+			groupArray[0] = "";
+		}
+		// 2.查询集团区域信息
+		SaasAreaQueryVO queryVO = new SaasAreaQueryVO();
+		queryVO.setAreaType(SaasCommonConstant.STR_STATUS_1);		//1-底层区域
+		List<SaasArea> areaList = this.saasAreaProjectHandler.querySaasAreaList(queryVO, true);
+		if (CollectionUtil.isNotEmpty(areaList)) {
+			areaMap = new HashMap<String, List<String>>();
+			for (SaasArea saasArea : areaList) {
+				String groupCode = saasArea.getGroupCode();
+				String key = temp.get(groupCode);
+				if (StringUtil.isNotBlank(key)) {
+					if (areaMap.containsKey(key)) {
+						areaMap.get(key).add(saasArea.getAreaName());
+					} else {
+						areaMap.put(key, Lists.newArrayList(saasArea.getAreaName()));
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * 设置单个下拉框
+	 */
+	@Override
+	public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
+		// 1.设置集团下拉框
+		Sheet sheet = writeSheetHolder.getSheet();
+		DataValidationHelper helper = sheet.getDataValidationHelper();
+		CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 500, 1, 1);
+		DataValidationConstraint constraint = helper.createExplicitListConstraint(groupArray);
+		DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
+		// 阻止输入非下拉选项的值
+		dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
+		// 处理Excel兼容性问题
+		if (dataValidation instanceof XSSFDataValidation) {
+			dataValidation.setSuppressDropDownArrow(true);
+			dataValidation.setShowErrorBox(true);
+		} else {
+			dataValidation.setSuppressDropDownArrow(false);
+		}
+		sheet.addValidationData(dataValidation);
+		
+		// 设置级联下拉框
+		if (areaMap != null) {
+			Workbook workbook = writeWorkbookHolder.getWorkbook();
+			Sheet hideSheet = workbook.getSheet("area");
+			if (hideSheet == null) {
+				hideSheet = workbook.createSheet("area");
+				// 这一行作用是将此sheet隐藏,功能未完成时注释此行,可以查看隐藏sheet中信息是否正确
+				workbook.setSheetHidden(workbook.getSheetIndex(hideSheet), true);
+				// 设置第一行,存集团信息
+				int rowId = 0;
+		        Iterator<String> keyIterator = areaMap.keySet().iterator();
+				while (keyIterator.hasNext()) {
+					String key = keyIterator.next();			// 集团编码
+					List<String> son = areaMap.get(key);		// 集团下底层分区
+					Row row = hideSheet.createRow(rowId++);		// 集团下底层分区所在行
+					row.createCell(0).setCellValue(key);		// 第一列为父名称,即集团编码
+					
+					for (int i = 0; i < son.size(); i++) {		// 此行依次填充底层分区信息
+						Cell cell = row.createCell(i + 1);
+						cell.setCellValue(son.get(i));			
+					}
+					
+					// 添加名称管理器 从第几列、第几行开始引用 ,总共多少列
+					String range = ExcelUtil.getRange(1, rowId, son.size());	
+					Name name = workbook.createName();
+					name.setNameName(key);
+					String formula = "area!" + range;
+					name.setRefersToFormula(formula);
+				}
+			}
+			
+			// 这是级联下拉实现
+			CellRangeAddressList areaCellRangeAddressList = new CellRangeAddressList(1, 500, 2, 2);
+			DataValidationConstraint areaConstraint = helper.createFormulaListConstraint("INDIRECT($B" + 2 + ")");
+	        DataValidation areaValidation = helper.createValidation(areaConstraint, areaCellRangeAddressList);
+	        // 阻止输入非下拉选项的值
+	        areaValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
+	 		// 处理Excel兼容性问题
+	 		if (areaValidation instanceof XSSFDataValidation) {
+	 			areaValidation.setSuppressDropDownArrow(true);
+	 			areaValidation.setShowErrorBox(true);
+	 		} else {
+	 			areaValidation.setSuppressDropDownArrow(false);
+	 		}
+	        sheet.addValidationData(areaValidation);
+		}
+	}
+
+}

+ 247 - 0
saas-account/src/main/java/com/persagy/person/manage/SaasRoleMenuHandler.java

@@ -0,0 +1,247 @@
+package com.persagy.person.manage;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.google.common.collect.Lists;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.exception.BusinessException;
+import com.persagy.common.utils.StringUtil;
+import com.persagy.person.pojo.dto.SaasAccountRole;
+import com.persagy.person.pojo.dto.SaasFunction;
+import com.persagy.person.pojo.dto.SaasMenu;
+import com.persagy.person.pojo.dto.SaasRole;
+import com.persagy.person.pojo.dto.SaasRoleMenu;
+import com.persagy.person.pojo.vo.auth.SaasMenuFunctionVO;
+import com.persagy.person.pojo.vo.role.SaasRoleDeleteVO;
+import com.persagy.person.service.ISaasAccountRoleService;
+import com.persagy.person.service.ISaasFunctionService;
+import com.persagy.person.service.ISaasMenuService;
+import com.persagy.person.service.ISaasRoleMenuService;
+import com.persagy.person.service.ISaasRoleService;
+
+import cn.hutool.core.collection.CollectionUtil;
+
+/**
+ * 角色菜单管理
+ * 
+ * @version
+ * @description
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月15日: 上午10:49:15
+ */
+@Component
+public class SaasRoleMenuHandler {
+
+    @Autowired
+    private ISaasRoleService saasRoleService;
+    
+	@Autowired
+	private ISaasMenuService saasMenuService;
+	
+    @Autowired
+    private ISaasFunctionService saasFunctionService;
+    
+    @Autowired
+    private ISaasRoleMenuService saasRoleMenuService;
+    
+	@Autowired
+    private ISaasAccountRoleService saasAccountRoleService;
+    
+	/**
+	 * 查询账号菜单功能权限树,菜单定义和角色定义编码相同,所以这里应该同步传递
+	 * 
+	 * @param accountId
+	 * @param groupCode
+	 * @param isAdmin 是否为超管 true-是
+	 * @param isMenu 是否仅查询出菜单树,true-是
+	 * @return 空集合或数据菜单树
+	 */
+	public List<SaasMenu> querySaasMenuTree(String accountId, String groupCode, boolean isAdmin, boolean isMenu) {
+		// 1.获取此账号对应菜单集合
+		List<SaasMenu> menuTree = null;
+		if (isAdmin) {
+			LambdaQueryWrapper<SaasMenu> queryWrapper = new SaasMenu.Builder().createQueryWrapper().menuTypeEq(SaasCommonConstant.STR_STATUS_0).builderQueryWrapper();
+			menuTree = this.saasMenuService.list(queryWrapper);
+		} else {
+			menuTree = this.saasMenuService.querySaasMenuTree(accountId, groupCode, SaasCommonConstant.STATUS_1);
+		}
+		if (CollectionUtil.isEmpty(menuTree)) {
+			return Lists.newArrayList();
+		}
+		// 2.转为菜单树
+		List<SaasMenu> topMenus = new ArrayList<SaasMenu>();
+		for (int i = menuTree.size() - 1; i >= 0; i--) {
+			SaasMenu saasMenu = menuTree.get(i);
+			if (StringUtil.isBlank(saasMenu.getParentId())) {
+				topMenus.add(saasMenu);
+				menuTree.remove(i);
+			}
+		}
+		List<SaasMenu> parents = topMenus.stream().sorted(Comparator.comparing(SaasMenu::getMenuSort)).collect(Collectors.toList());
+		this.setMenuChildrens(accountId, menuTree, parents, isAdmin, !isMenu);
+		return parents;
+	}
+
+	/**
+	 * 生成菜单树
+	 * @param accountId 为null时,isAdmin 为true
+	 * @param menuTree
+	 * @param parents
+	 * @param isAdmin 是否为超管 true-是
+	 * @param menuAndFun 
+	 */
+	public void setMenuChildrens(String accountId, List<SaasMenu> menuTree, List<SaasMenu> parents, boolean isAdmin, boolean menuAndFun) {
+		for (SaasMenu parent : parents) {
+			if (StringUtil.isBlank(parent.getMenuId())) {
+				parent.setMenuId(parent.getId());
+			}
+			if (menuAndFun && StringUtil.isNotBlank(parent.getMenuUrl())) {
+				// 查询出对应功能点集合
+				List<SaasFunction> functions = null;
+				if (isAdmin) {
+					LambdaQueryWrapper<SaasFunction> queryWrapper = new SaasFunction.Builder().createQueryWrapper().menuIdEq(parent.getMenuId()).builderQueryWrapper();
+					functions = this.saasFunctionService.list(queryWrapper.orderByAsc(SaasFunction::getFunSort));
+				} else {
+					functions = this.saasFunctionService.queryAccountFunctionList(accountId, parent.getGroupCode(), parent.getMenuId());
+				}
+				parent.setFunctions(CollectionUtil.isEmpty(functions) ? Lists.newArrayList() : functions);
+			}
+			
+			List<SaasMenu> childrens = new ArrayList<SaasMenu>();
+			for (int i = menuTree.size() - 1; i >= 0; i--) {
+				SaasMenu saasMenu = menuTree.get(i);
+				if (parent.getMenuId().equals(saasMenu.getParentId())) {
+					childrens.add(saasMenu);
+					menuTree.remove(i);
+				}
+			}
+			
+			List<SaasMenu> nextTops = childrens.stream().sorted(Comparator.comparing(SaasMenu::getMenuSort)).collect(Collectors.toList());
+			parent.setChildrens(nextTops);
+			this.setMenuChildrens(accountId, menuTree, nextTops, isAdmin, menuAndFun);
+		}
+	}
+	
+	/**
+	 * 删除角色,级联删除账号角色,角色菜单的关联关系
+	 * 
+	 * @param deleteVO
+	 */
+	@Transactional
+	public boolean deleteSaasRole(SaasRoleDeleteVO deleteVO) {
+		LambdaUpdateWrapper<SaasRole> updateWrapper = new SaasRole.Builder().createUpdateWrapper().idEq(deleteVO.getId())
+				.validEq(SaasCommonConstant.STATUS_1).builderUpdateWrapper();
+		updateWrapper.set(SaasRole::getUpdateUser, deleteVO.getAccountId());
+		updateWrapper.set(SaasRole::getValid, SaasCommonConstant.STATUS_0);
+		boolean result = this.saasRoleService.update(updateWrapper);
+		if (result) {
+			// 1.级联删除账号和角色关联关系
+			LambdaQueryWrapper<SaasAccountRole> accountRoleWrapper = new SaasAccountRole.Builder().createQueryWrapper().roleIdEq(deleteVO.getId()).builderQueryWrapper();
+			this.saasAccountRoleService.remove(accountRoleWrapper);
+			// 2.级联删除角色和菜单的关联关系
+			LambdaQueryWrapper<SaasRoleMenu> roleMenuWrapper = new SaasRoleMenu.Builder().createQueryWrapper().roleIdEq(deleteVO.getId()).builderQueryWrapper();
+			this.saasRoleMenuService.remove(roleMenuWrapper);
+		}
+		return result;
+	}
+	
+	/**
+	 * 删除菜单,级联删除,角色、菜单、功能三者关联关系数据
+	 * 
+	 * @param menuId
+	 * @return
+	 */
+	@Transactional
+	public boolean deleteSaasMenu(String menuId) {
+		boolean result = this.saasMenuService.removeById(menuId);
+		if (result) {
+			// 1.删除此菜单下功能
+			LambdaQueryWrapper<SaasFunction> funWrapper = new SaasFunction.Builder().createQueryWrapper().menuIdEq(menuId).builderQueryWrapper();
+			this.saasFunctionService.remove(funWrapper);
+			// 2.删除此功能对应的菜单、角色关系数据
+			LambdaQueryWrapper<SaasRoleMenu> roleMenuWrapper = new SaasRoleMenu.Builder().createQueryWrapper().menuIdEq(menuId).builderQueryWrapper();
+			this.saasRoleMenuService.remove(roleMenuWrapper);
+		}
+		return result;
+	}
+
+	/**
+	 * 删除功能,级联删除菜单、功能关系
+	 * @param menuId 
+	 * 
+	 * @param id
+	 * @return
+	 */
+	@Transactional
+	public boolean deleteSaasFunction(String funId, String menuId) {
+		LambdaQueryWrapper<SaasFunction> queryWrapper = new SaasFunction.Builder().createQueryWrapper().menuIdEq(menuId).idEq(funId).builderQueryWrapper();
+		boolean result = this.saasFunctionService.removeById(queryWrapper);
+		if (result) {
+			// 1.删除此功能对应的菜单、角色关系数据
+			LambdaQueryWrapper<SaasRoleMenu> roleMenuWrapper = new SaasRoleMenu.Builder().createQueryWrapper().menuIdEq(menuId).functionIdEq(funId).builderQueryWrapper();
+			this.saasRoleMenuService.remove(roleMenuWrapper);
+		}
+		return result;
+	}
+	
+	/**
+	 * 先删后新增,仅删除此账号角色下的所有菜单功能点的关联关系,并重新新增
+	 * 
+	 * @param batchVO
+	 * @return
+	 */
+	@Transactional
+	public boolean resetSaasRoleMenu(String groupCode, String roleId, List<SaasMenuFunctionVO> auths) {
+		LambdaQueryWrapper<SaasRoleMenu> roleMenuWrapper = new SaasRoleMenu.Builder().createQueryWrapper().roleIdEq(roleId).builderQueryWrapper();
+		this.saasRoleMenuService.remove(roleMenuWrapper);
+		// 1.批量新增
+		boolean result = this.saasRoleMenuService.batchCreateSaasRoleMenu(groupCode, roleId, auths);
+		if (!result) {
+			throw new BusinessException("先删后新增角色菜单功能权限失败");
+		}
+		return result;
+	}
+	
+	/**
+	 * 创建角色,同时添加菜单关联关系
+	 * @param saasRole
+	 * @param auths
+	 * @return
+	 */
+	@Transactional
+	public boolean createSaasRole(SaasRole saasRole, List<SaasMenuFunctionVO> auths) {
+		// 1.创建角色信息
+		boolean result = this.saasRoleService.save(saasRole);
+		if (result && CollectionUtil.isNotEmpty(auths)) {
+			// 2.删除并创建角色信息
+			this.resetSaasRoleMenu(saasRole.getGroupCode(), saasRole.getId(), auths);
+		}
+		return result;
+	}
+
+	/**
+	 * 更新角色,同时更新菜单关联关系
+	 * @param saasRole
+	 * @param auths
+	 * @return
+	 */
+	@Transactional
+	public boolean updateSaasRole(SaasRole saasRole, List<SaasMenuFunctionVO> auths) {
+		boolean result = this.saasRoleService.updateById(saasRole);
+		if (result && CollectionUtil.isNotEmpty(auths)) {
+			this.resetSaasRoleMenu(saasRole.getGroupCode(), saasRole.getId(), auths);
+		}
+		return result;
+	}
+
+}

+ 32 - 0
saas-account/src/main/java/com/persagy/person/mapper/SaasAccountMapper.java

@@ -0,0 +1,32 @@
+package com.persagy.person.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.person.pojo.dto.SaasAccount;
+
+/**
+ * 账号信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Mapper
+public interface SaasAccountMapper extends BaseMapper<SaasAccount> {
+
+	/**
+	 * 获取账号列表,此方法会关联出集团名称信息
+	 * 
+	 * @param saasAccount
+	 * @param startRow
+	 * @param size
+	 * @return
+	 */
+	List<SaasAccount> queryAccountGroupList(@Param("account") SaasAccount saasAccount, @Param("startRow") int startRow, @Param("size") int size);
+
+}

+ 49 - 0
saas-account/src/main/java/com/persagy/person/mapper/SaasAccountProjectMapper.java

@@ -0,0 +1,49 @@
+package com.persagy.person.mapper;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.person.pojo.dto.SaasAccountProject;
+import com.persagy.person.pojo.vo.auth.AccountProjectResetVO;
+
+/**
+ * 账号-集团项目关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Mapper
+public interface SaasAccountProjectMapper extends BaseMapper<SaasAccountProject> {
+
+	/**
+	 * 批量创建账号集团项目信息
+	 * 
+	 * @param accountId
+	 * @param projectIds
+	 * @return
+	 */
+	Integer batchInsertSaasAccountProject(@Param("accountId") String accountId, @Param("auths") List<AccountProjectResetVO> auths);
+
+	/**
+	 * 获取已被分配的集团区域ID集合
+	 * @param accountId
+	 * @param groupCode
+	 * @return
+	 */
+	Set<String> queryAccountAreaIds(@Param("accountId") String accountId, @Param("groupCode") String groupCode);
+	
+	/**
+	 * 更新或新增账号-集团区域项目关联关系
+	 * 
+	 * @param datas
+	 * @return
+	 */
+	Integer replaceAccountProject(@Param("datas") List<SaasAccountProject> datas);
+	
+}

+ 42 - 0
saas-account/src/main/java/com/persagy/person/mapper/SaasAccountRoleMapper.java

@@ -0,0 +1,42 @@
+package com.persagy.person.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.person.pojo.dto.SaasAccountRole;
+import com.persagy.person.pojo.vo.auth.SaasAccountRoleVO;
+
+/**
+ * 账号-角色关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Mapper
+public interface SaasAccountRoleMapper extends BaseMapper<SaasAccountRole> {
+
+	/**
+	 * 获取账号ID集合
+	 * 
+	 * @param groupCode
+	 * @param roleId
+	 * @return
+	 */
+	Integer isAllowDeleteRole(@Param("groupCode") String groupCode, @Param("roleId") String roleId, @Param("valid") Integer valid);
+	
+	/**
+	 * 先删除,在新增,批量插入账号角色关联关系,主要服务于新建账号信息时同时新增
+	 * 
+	 * @param groupCode
+	 * @param accountId
+	 * @param roles
+	 * @return
+	 */
+	Integer batchInsertSaasAccountRole(@Param("groupCode") String groupCode, @Param("accountId") String accountId, @Param("roles") List<SaasAccountRoleVO> roles);
+
+}

+ 30 - 0
saas-account/src/main/java/com/persagy/person/mapper/SaasAreaMapper.java

@@ -0,0 +1,30 @@
+package com.persagy.person.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.person.pojo.dto.SaasArea;
+
+/**
+ * 区域信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Mapper
+public interface SaasAreaMapper extends BaseMapper<SaasArea> {
+
+	/**
+	 * 获取被允许访问的区域信息
+	 * 
+	 * @param saasArea
+	 * @return
+	 */
+	List<SaasArea> queryAllowSaasAreaList(@Param("accountId") String accountId, @Param("area") SaasArea saasArea);
+
+}

+ 43 - 0
saas-account/src/main/java/com/persagy/person/mapper/SaasFunctionMapper.java

@@ -0,0 +1,43 @@
+package com.persagy.person.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.person.pojo.dto.SaasFunction;
+
+/**
+ * 功能信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Mapper
+public interface SaasFunctionMapper extends BaseMapper<SaasFunction> {
+
+	/**
+	 * 查询出该账号下某菜单的功能点信息集合,关联查询
+	 * 
+	 * @param accountId
+	 * @param groupCode
+	 * @param roleId
+	 * @param menuId
+	 * @return
+	 */
+	List<SaasFunction> queryAccountFunctionList(@Param("accountId") String accountId, @Param("groupCode") String groupCode, @Param("menuId") String menuId);
+	
+	/**
+	 * 查询出该角色下某菜单的功能点信息集合,关联查询
+	 * 
+	 * @param groupCode
+	 * @param roleId
+	 * @param menuId
+	 * @return
+	 */
+	List<SaasFunction> queryRoleFunctionList(@Param("groupCode") String groupCode, @Param("roleId") String roleId, @Param("menuId") String menuId);
+	
+}

+ 39 - 0
saas-account/src/main/java/com/persagy/person/mapper/SaasGroupMapper.java

@@ -0,0 +1,39 @@
+package com.persagy.person.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.person.pojo.dto.SaasGroup;
+
+/**
+ * 集团信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Mapper
+public interface SaasGroupMapper extends BaseMapper<SaasGroup> {
+	
+	/**
+	 * 查询集团信息列表,表关联查询(权限控制)
+	 * @param saasGroup
+	 * @param accountId
+	 * @return
+	 */
+	List<SaasGroup> queryAllowGroupInfo(@Param("group") SaasGroup saasGroup, @Param("accountId") String accountId);
+
+	/**
+	 * 查询没有项目信息的被选中的集团信息
+	 * 
+	 * @param groupCode
+	 * @param accountId
+	 * @return
+	 */
+	List<SaasGroup> queryGroupAndEmptyProject(@Param("groupCode") String groupCode, @Param("accountId") String accountId);
+	
+}

+ 39 - 0
saas-account/src/main/java/com/persagy/person/mapper/SaasMenuMapper.java

@@ -0,0 +1,39 @@
+package com.persagy.person.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.person.pojo.dto.SaasMenu;
+
+/**
+ * 菜单信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Mapper
+public interface SaasMenuMapper extends BaseMapper<SaasMenu> {
+	
+	/**
+	 * 获取菜单树
+	 * @param accountId
+	 * @param groupCode
+	 * @param valid
+	 * @return
+	 */
+	List<SaasMenu> querySaasMenuTree(@Param("accountId") String accountId, @Param("groupCode") String groupCode, @Param("valid") Integer valid);
+	
+	/**
+	 * 查询出此角色下,所有不存在功能点的菜单集合
+	 * @param groupCode
+	 * @param roleId
+	 * @return
+	 */
+	List<SaasMenu> queryMenuAndEmptyFunction(@Param("groupCode") String groupCode, @Param("roleId") String roleId);
+	
+}

+ 88 - 0
saas-account/src/main/java/com/persagy/person/mapper/SaasProjectMapper.java

@@ -0,0 +1,88 @@
+package com.persagy.person.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.person.pojo.dto.SaasProject;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Mapper
+public interface SaasProjectMapper extends BaseMapper<SaasProject> {
+
+	/**
+	 * 项目列表查询
+	 * 
+	 * @param saasProject
+	 * @param startRow
+	 * @param size
+	 * @return
+	 */
+	List<SaasProject> querySaasProjectList(@Param("project") SaasProject saasProject, @Param("startRow") Integer startRow, @Param("size") Integer size);
+	
+	/**
+	 * 分页查询时,获取总记录数
+	 * 
+	 * @param saasProject
+	 * @return
+	 */
+	Integer queryCountMoreProject(@Param("project") SaasProject saasProject);
+		
+	/**
+	 * 获取项目集合信息,关联查询
+	 * 
+	 * @param saasProject
+	 * @param page
+	 * @param size
+	 * @return
+	 */
+	List<SaasProject> queryMoreProjectInfo(@Param("project") SaasProject saasProject, @Param("startRow") Integer startRow, @Param("size") Integer size);
+
+	/**
+	 * 查询该账户可允许访问的集团项目,权限表关联查询,默认项目名称正序排序
+	 * 
+	 * @param groupCode
+	 * @param accountId
+	 * @param valid 1-可用,0-不可用
+	 * @return
+	 */
+	List<SaasProject> queryAllowGroupProjectList(@Param("groupCode") String groupCode, @Param("accountId") String accountId, @Param("valid") Integer valid);
+	
+	/**
+	 * 批量插入项目信息
+	 * 
+	 * @param list
+	 * @return
+	 */
+	Integer batchInsertProjectData(@Param("projects") List<SaasProject> projects);
+	
+	/**
+	 * 批量更新项目所属区域
+	 * 
+	 * @param saasProject
+	 * @param projectIds
+	 * @return
+	 */
+	Integer batchUpdateProjectArea(@Param("project") SaasProject saasProject, @Param("projectIds") List<String> projectIds);
+
+	/**
+	 * 查询出能够被访问的项目总数
+	 * 
+	 * @param groupCode 集团编码
+	 * @param accountId 账号ID
+	 * @param areaId 底层区域ID
+	 * @return
+	 */
+	Integer countAllowProjectNum(@Param("groupCode") String groupCode, @Param("accountId") String accountId, 
+			@Param("areaId") String areaId, @Param("valid") Integer valid);
+	
+}

+ 30 - 0
saas-account/src/main/java/com/persagy/person/mapper/SaasRoleMapper.java

@@ -0,0 +1,30 @@
+package com.persagy.person.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.person.pojo.dto.SaasRole;
+
+/**
+ * 角色信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Mapper
+public interface SaasRoleMapper extends BaseMapper<SaasRole> {
+	
+	/**
+	 * 根据账号ID,获取该账号所拥有的所有角色
+	 * @param accountId
+	 * @param valid
+	 * @return
+	 */
+	List<SaasRole> querySaasRoleList(@Param("accountId") String accountId, @Param("valid") Integer valid);
+	
+}

+ 49 - 0
saas-account/src/main/java/com/persagy/person/mapper/SaasRoleMenuMapper.java

@@ -0,0 +1,49 @@
+package com.persagy.person.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.persagy.person.pojo.dto.SaasRoleMenu;
+import com.persagy.person.pojo.vo.auth.SaasMenuFunctionVO;
+
+/**
+ * 角色-菜单功能关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Mapper
+public interface SaasRoleMenuMapper extends BaseMapper<SaasRoleMenu> {
+
+	/**
+	 * 批量创建角色对应的菜单功能权限
+	 * 
+	 * @param batchVO
+	 * @return
+	 */
+	Integer batchCreateSaasRoleMenu(@Param("groupCode") String groupCode, @Param("roleId") String roleId, @Param("auths") List<SaasMenuFunctionVO> auths);
+
+	/**
+	 * 统计出有效的角色数
+	 * 
+	 * @param groupCode
+	 * @param menuId
+	 * @param status1
+	 * @return
+	 */
+	Integer isAllowDeleteMenu(@Param("groupCode") String groupCode, @Param("menuId") String menuId, @Param("valid") Integer valid);
+	
+	/**
+	 * 获取此角色下菜单数量
+	 * 
+	 * @param roleId
+	 * @return
+	 */
+	Integer countMenu(@Param("roleId") String roleId);
+	
+}

+ 29 - 0
saas-account/src/main/java/com/persagy/person/mq/CommonConfirmCallback.java

@@ -0,0 +1,29 @@
+package com.persagy.person.mq;
+
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.connection.CorrelationData;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月29日:	下午3:59:52
+ */
+@Slf4j
+public class CommonConfirmCallback implements RabbitTemplate.ConfirmCallback {
+
+	@Override
+	public void confirm(CorrelationData correlationData, boolean ack, String cause) {
+		Message message = correlationData.getReturnedMessage();
+		String msg = new String(message.getBody());
+		log.info("correlationData: " + correlationData);
+		log.info("correlationData msg: " + msg);
+		log.info("ack: " + ack);
+		log.info("cause: " + cause);
+	}
+
+}

+ 60 - 0
saas-account/src/main/java/com/persagy/person/mq/CommonTopicProducer.java

@@ -0,0 +1,60 @@
+package com.persagy.person.mq;
+
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson.JSON;
+import com.persagy.person.config.ApplicationProperties;
+import com.persagy.person.pojo.dto.SaasAccount;
+import com.persagy.person.pojo.dto.SaasGroup;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月2日:	下午2:24:08
+ */
+@Slf4j
+@Component
+public class CommonTopicProducer {
+	
+	@Autowired
+	private RabbitTemplate rabbitTemplate;
+	
+	@Autowired
+	private ApplicationProperties properties;
+	
+	/**
+	 * 创建集团信息时,投递至mq
+	 * 
+	 * @param type 类型 create-创建,update-更新
+	 */
+	public void sendGroupInfo(SaasGroup saasGroup, String type) {
+		if (properties.isRaabitmqEnable()) {
+			saasGroup.setType(type);
+			String message = JSON.toJSONString(saasGroup);
+			log.info("send rabbitmq group message to " + properties.getCommonExchange() + " : " + message);
+			this.rabbitTemplate.convertAndSend(properties.getCommonExchange(), properties.getGroupRouteKey(), message);
+		}
+	}
+	
+	/**
+	 * 创建集团管理员账号信息时,投递至mq
+	 * 
+	 * @param type 类型 create-创建,update-更新
+	 */
+	public void sendAccountInfo(SaasAccount saasAccount, String type) {
+		if (properties.isRaabitmqEnable()) {
+			saasAccount.setType(type);
+			saasAccount.setPassword(null);
+			String message = JSON.toJSONString(saasAccount);
+			log.info("send rabbitmq account message to " + properties.getCommonExchange() + " : " + message);
+			this.rabbitTemplate.convertAndSend(properties.getCommonExchange(), properties.getAccountRouteKey(), message);
+		}
+	}
+
+}

+ 411 - 0
saas-account/src/main/java/com/persagy/person/pojo/dto/SaasAccount.java

@@ -0,0 +1,411 @@
+package com.persagy.person.pojo.dto;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.persagy.common.annotation.IdGeneratorPrefix;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseEntity;
+import com.persagy.common.utils.StringUtil;
+
+import cn.hutool.core.collection.CollectionUtil;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 账号信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode(callSuper = false)
+@TableName("saas_account")
+@IdGeneratorPrefix(SaasCommonConstant.SAAS_ACCOUNT_ID_PREFIX)
+public class SaasAccount extends BaseEntity<SaasAccount> {
+	private static final long serialVersionUID = 3222916987593249671L;
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupCode; // 集团编码
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String appId; // 应用ID, PC-电脑端,APP-手机端
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String username; // 登录用户名
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String password; // 登录密码
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String phoneNum; // 手机号
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String mail; // 邮箱
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String headPortrait; // 头像,图片URL
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String accountType;		//账号类型, 0-超级管理员(所有集团),1-单集团管理员(单集团),2-普通账号
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String accountBelong;	//账号所属, 0-运维系统账号,1-业务账号
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String accountSource; // 账号来源
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date lastLoginTime; // 账号上一次登录时间
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String lastLoginIp; // 账号上一次登录IP
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date validStartTime; // 账号有效期的开始时间
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date validEndTime;  // 账号有效期的结束时间
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String validLast;	//账号有效期,0-期内有效,1-永久有效
+
+	@TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date createTime; 	// 创建时间
+
+	@TableField(fill = FieldFill.INSERT_UPDATE, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date updateTime; 	// 更新时间
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String updateUser; // 最后一次操作者ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String remark; // 备注
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Integer valid; // 0-不可用,1-可用
+
+	@TableField(exist = false)
+	private String groupName; 		// 集团名称
+	
+	@TableField(exist = false)
+	private String type;	//类型 create-创建,update-更新
+	
+	@TableField(exist = false)
+	private List<SaasGroup> groups;	//集团信息集合
+	
+	@TableField(exist = false)
+	private int projectNum;		//项目个数
+
+	@TableField(exist = false)
+	private List<SaasRole> roles;	//角色集合
+	
+	public static class Builder {
+
+		private LambdaQueryWrapper<SaasAccount> queryWrapper = null;
+
+		private LambdaUpdateWrapper<SaasAccount> updateWrapper = null;
+
+		public Builder createQueryWrapper() {
+			queryWrapper = new LambdaQueryWrapper<SaasAccount>();
+			return this;
+		}
+
+		public Builder createUpdateWrapper() {
+			updateWrapper = new LambdaUpdateWrapper<SaasAccount>();
+			return this;
+		}
+
+		public Builder idEq(String id) {
+			if (StringUtil.isNotBlank(id)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getId, id);
+				} else {
+					queryWrapper.eq(SaasAccount::getId, id);
+				}
+			}
+			return this;
+		}
+		
+		public Builder idIn(Set<String> ids) {
+			if (CollectionUtil.isNotEmpty(ids)) {
+				if (updateWrapper != null) {
+					updateWrapper.in(SaasAccount::getId, ids);
+				} else {
+					queryWrapper.in(SaasAccount::getId, ids);
+				}
+			}
+			return this;
+		}
+
+		public Builder groupCodeEq(String groupCode) {
+			if (StringUtil.isNotBlank(groupCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getGroupCode, groupCode);
+				} else {
+					queryWrapper.eq(SaasAccount::getGroupCode, groupCode);
+				}
+			}
+			return this;
+		}
+
+		public Builder appIdEq(String appId) {
+			if (StringUtil.isNotBlank(appId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getAppId, appId);
+				} else {
+					queryWrapper.eq(SaasAccount::getAppId, appId);
+				}
+			}
+			return this;
+		}
+
+		public Builder usernameEq(String username) {
+			if (StringUtil.isNotBlank(username)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getUsername, username);
+				} else {
+					queryWrapper.eq(SaasAccount::getUsername, username);
+				}
+			}
+			return this;
+		}
+
+		public Builder usernameLike(String username) {
+			if (StringUtil.isNotBlank(username)) {
+				if (updateWrapper != null) {
+					updateWrapper.like(SaasAccount::getUsername, username);
+				} else {
+					queryWrapper.like(SaasAccount::getUsername, username);
+				}
+			}
+			return this;
+		}
+
+		public Builder passwordEq(String password) {
+			if (StringUtil.isNotBlank(password)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getPassword, password);
+				} else {
+					queryWrapper.eq(SaasAccount::getPassword, password);
+				}
+			}
+			return this;
+		}
+
+		public Builder phoneNumEq(String phoneNum) {
+			if (StringUtil.isNotBlank(phoneNum)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getPhoneNum, phoneNum);
+				} else {
+					queryWrapper.eq(SaasAccount::getPhoneNum, phoneNum);
+				}
+			}
+			return this;
+		}
+
+		public Builder mailEq(String mail) {
+			if (StringUtil.isNotBlank(mail)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getMail, mail);
+				} else {
+					queryWrapper.eq(SaasAccount::getMail, mail);
+				}
+			}
+			return this;
+		}
+
+		public Builder headPortraitEq(String headPortrait) {
+			if (StringUtil.isNotBlank(headPortrait)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getHeadPortrait, headPortrait);
+				} else {
+					queryWrapper.eq(SaasAccount::getHeadPortrait, headPortrait);
+				}
+			}
+			return this;
+		}
+
+		public Builder accountTypeEq(String accountType) {
+			if (StringUtil.isNotBlank(accountType)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getAccountType, accountType);
+				} else {
+					queryWrapper.eq(SaasAccount::getAccountType, accountType);
+				}
+			}
+			return this;
+		}
+		
+		public Builder accountSourceEq(String accountSource) {
+			if (StringUtil.isNotBlank(accountSource)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getAccountSource, accountSource);
+				} else {
+					queryWrapper.eq(SaasAccount::getAccountSource, accountSource);
+				}
+			}
+			return this;
+		}
+		
+		public Builder accountBelongEq(String accountBelong) {
+			if (StringUtil.isNotBlank(accountBelong)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getAccountBelong, accountBelong);
+				} else {
+					queryWrapper.eq(SaasAccount::getAccountBelong, accountBelong);
+				}
+			}
+			return this;
+		}
+
+		public Builder lastLoginTimeEq(Date lastLoginTime) {
+			if (null != lastLoginTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getLastLoginTime, lastLoginTime);
+				} else {
+					queryWrapper.eq(SaasAccount::getLastLoginTime, lastLoginTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder lastLoginIpEq(String lastLoginIp) {
+			if (StringUtil.isNotBlank(lastLoginIp)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getLastLoginIp, lastLoginIp);
+				} else {
+					queryWrapper.eq(SaasAccount::getLastLoginIp, lastLoginIp);
+				}
+			}
+			return this;
+		}
+
+		public Builder validStartTimeEq(Date validStartTime) {
+			if (null != validStartTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getValidStartTime, validStartTime);
+				} else {
+					queryWrapper.eq(SaasAccount::getValidStartTime, validStartTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder validEndTimeEq(Date validEndTime) {
+			if (null != validEndTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getValidEndTime, validEndTime);
+				} else {
+					queryWrapper.eq(SaasAccount::getValidEndTime, validEndTime);
+				}
+			}
+			return this;
+		}
+		
+		/**
+		 * 当前时间是否在有效期内
+		 * @param validEndTime
+		 * @return
+		 */
+		public Builder validDateBetween(Date currentDate) {
+			if (null != currentDate) {
+				if (updateWrapper != null) {
+					updateWrapper.le(SaasAccount::getValidStartTime, currentDate);
+					updateWrapper.ge(SaasAccount::getValidEndTime, currentDate);
+				} else {
+					queryWrapper.le(SaasAccount::getValidStartTime, currentDate);
+					queryWrapper.ge(SaasAccount::getValidEndTime, currentDate);
+				}
+			}
+			return this;
+		}
+
+		public Builder validLastEq(String validLast) {
+			if (StringUtil.isNotBlank(validLast)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getValidLast, validLast);
+				} else {
+					queryWrapper.eq(SaasAccount::getValidLast, validLast);
+				}
+			}
+			return this;
+		}
+		
+		public Builder createTimeEq(Date createTime) {
+			if (null != createTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getCreateTime, createTime);
+				} else {
+					queryWrapper.eq(SaasAccount::getCreateTime, createTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateTimeEq(Date updateTime) {
+			if (null != updateTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getUpdateTime, updateTime);
+				} else {
+					queryWrapper.eq(SaasAccount::getUpdateTime, updateTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateUserEq(String updateUser) {
+			if (StringUtil.isNotBlank(updateUser)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getUpdateUser, updateUser);
+				} else {
+					queryWrapper.eq(SaasAccount::getUpdateUser, updateUser);
+				}
+			}
+			return this;
+		}
+
+		public Builder remarkEq(String remark) {
+			if (StringUtil.isNotBlank(remark)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getRemark, remark);
+				} else {
+					queryWrapper.eq(SaasAccount::getRemark, remark);
+				}
+			}
+			return this;
+		}
+
+		public Builder validEq(Integer valid) {
+			if (null != valid) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccount::getValid, valid);
+				} else {
+					queryWrapper.eq(SaasAccount::getValid, valid);
+				}
+			}
+			return this;
+		}
+
+		public LambdaQueryWrapper<SaasAccount> builderQueryWrapper() {
+			return queryWrapper;
+		}
+
+		public LambdaUpdateWrapper<SaasAccount> builderUpdateWrapper() {
+			return updateWrapper;
+		}
+	}
+}

+ 112 - 0
saas-account/src/main/java/com/persagy/person/pojo/dto/SaasAccountProject.java

@@ -0,0 +1,112 @@
+package com.persagy.person.pojo.dto;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.persagy.common.utils.StringUtil;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 账号-集团项目关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode(callSuper = false)
+@TableName("saas_account_project")
+public class SaasAccountProject extends Model<SaasAccountProject> {
+	private static final long serialVersionUID = 5519395457650465434L;
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupCode; // 集团编码
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String accountId; // 账号ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String areaId; // 项目ID
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String projectId; // 项目ID
+	
+	public static class Builder {
+
+		private LambdaQueryWrapper<SaasAccountProject> queryWrapper = null;
+
+		private LambdaUpdateWrapper<SaasAccountProject> updateWrapper = null;
+
+		public Builder createQueryWrapper() {
+			queryWrapper = new LambdaQueryWrapper<SaasAccountProject>();
+			return this;
+		}
+
+		public Builder createUpdateWrapper() {
+			updateWrapper = new LambdaUpdateWrapper<SaasAccountProject>();
+			return this;
+		}
+
+		public Builder groupCodeEq(String groupCode) {
+			if (StringUtil.isNotBlank(groupCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccountProject::getGroupCode, groupCode);
+				} else {
+					queryWrapper.eq(SaasAccountProject::getGroupCode, groupCode);
+				}
+			}
+			return this;
+		}
+
+		public Builder accountIdEq(String accountId) {
+			if (StringUtil.isNotBlank(accountId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccountProject::getAccountId, accountId);
+				} else {
+					queryWrapper.eq(SaasAccountProject::getAccountId, accountId);
+				}
+			}
+			return this;
+		}
+
+		public Builder areaIdEq(String areaId) {
+			if (StringUtil.isNotBlank(areaId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccountProject::getAreaId, areaId);
+				} else {
+					queryWrapper.eq(SaasAccountProject::getAreaId, areaId);
+				}
+			}
+			return this;
+		}
+		
+		public Builder projectIdEq(String projectId) {
+			if (StringUtil.isNotBlank(projectId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccountProject::getProjectId, projectId);
+				} else {
+					queryWrapper.eq(SaasAccountProject::getProjectId, projectId);
+				}
+			}
+			return this;
+		}
+
+		public LambdaQueryWrapper<SaasAccountProject> builderQueryWrapper() {
+			return queryWrapper;
+		}
+
+		public LambdaUpdateWrapper<SaasAccountProject> builderUpdateWrapper() {
+			return updateWrapper;
+		}
+	}
+}

+ 133 - 0
saas-account/src/main/java/com/persagy/person/pojo/dto/SaasAccountRole.java

@@ -0,0 +1,133 @@
+package com.persagy.person.pojo.dto;
+
+import java.util.List;
+import java.util.Set;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.persagy.common.utils.StringUtil;
+
+import cn.hutool.core.collection.CollectionUtil;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 账号-角色关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode(callSuper = false)
+@TableName("saas_account_role")
+public class SaasAccountRole extends Model<SaasAccountRole> {
+	private static final long serialVersionUID = -6223601411225948734L;
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupCode; // 集团编码
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String accountId; // 账号ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String roleId; // 角色ID
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String casType;	//关联类型,0-主岗,1-副岗,2-业务超管默认角色
+	
+	@TableField(exist = false)
+	private List<SaasRole> roles; // 角色信息集合
+	
+	@TableField(exist = false)
+	private List<SaasMenu> menus; // 菜单信息集合-树形结构
+
+	public static class Builder {
+
+		private LambdaQueryWrapper<SaasAccountRole> queryWrapper = null;
+
+		private LambdaUpdateWrapper<SaasAccountRole> updateWrapper = null;
+
+		public Builder createQueryWrapper() {
+			queryWrapper = new LambdaQueryWrapper<SaasAccountRole>();
+			return this;
+		}
+
+		public Builder createUpdateWrapper() {
+			updateWrapper = new LambdaUpdateWrapper<SaasAccountRole>();
+			return this;
+		}
+
+		public Builder groupCodeEq(String groupCode) {
+			if (StringUtil.isNotBlank(groupCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccountRole::getGroupCode, groupCode);
+				} else {
+					queryWrapper.eq(SaasAccountRole::getGroupCode, groupCode);
+				}
+			}
+			return this;
+		}
+
+		public Builder accountIdEq(String accountId) {
+			if (StringUtil.isNotBlank(accountId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccountRole::getAccountId, accountId);
+				} else {
+					queryWrapper.eq(SaasAccountRole::getAccountId, accountId);
+				}
+			}
+			return this;
+		}
+		
+		public Builder accountIdIn(Set<String> accountIds) {
+			if (CollectionUtil.isNotEmpty(accountIds)) {
+				if (updateWrapper != null) {
+					updateWrapper.in(SaasAccountRole::getAccountId, accountIds);
+				} else {
+					queryWrapper.in(SaasAccountRole::getAccountId, accountIds);
+				}
+			}
+			return this;
+		}
+		
+		public Builder roleIdEq(String roleId) {
+			if (StringUtil.isNotBlank(roleId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccountRole::getRoleId, roleId);
+				} else {
+					queryWrapper.eq(SaasAccountRole::getRoleId, roleId);
+				}
+			}
+			return this;
+		}
+		
+		public Builder casTypeEq(String casType) {
+			if (StringUtil.isNotBlank(casType)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasAccountRole::getCasType, casType);
+				} else {
+					queryWrapper.eq(SaasAccountRole::getCasType, casType);
+				}
+			}
+			return this;
+		}
+		
+		public LambdaQueryWrapper<SaasAccountRole> builderQueryWrapper() {
+			return queryWrapper;
+		}
+
+		public LambdaUpdateWrapper<SaasAccountRole> builderUpdateWrapper() {
+			return updateWrapper;
+		}
+	}
+}

+ 235 - 0
saas-account/src/main/java/com/persagy/person/pojo/dto/SaasArea.java

@@ -0,0 +1,235 @@
+package com.persagy.person.pojo.dto;
+
+import java.util.Date;
+import java.util.List;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.persagy.common.annotation.IdGeneratorPrefix;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseEntity;
+import com.persagy.common.utils.StringUtil;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 区域信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode(callSuper = false)
+@TableName("saas_area")
+@IdGeneratorPrefix(SaasCommonConstant.SAAS_AREA_ID_PREFIX)
+public class SaasArea extends BaseEntity<SaasArea> {
+	private static final long serialVersionUID = -6778648944439996610L;
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupCode; // 集团编码
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String parentId; // 上级区域ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String areaCode; // 区域编码
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String areaName; // 区域名称
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String areaType; // 区域类别,0-非最底层区域,1-最底层区域
+
+	@TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date createTime; // 创建时间
+
+	@TableField(fill = FieldFill.INSERT_UPDATE, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date updateTime; // 更新时间
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String updateUser; // 最后一次操作者ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String remark; // 备注
+	
+	@TableField(exist = false)
+	private List<SaasArea> childrens;	//下级区域
+	
+	@TableField(exist = false)
+	private List<SaasProject> projects;		//底层区域对应的项目集合
+	
+	@TableField(exist = false)
+	private Integer projectNum;		//当前区域及其所有下级区域包含的所有项目数
+
+	public static class Builder {
+
+		private LambdaQueryWrapper<SaasArea> queryWrapper = null;
+
+		private LambdaUpdateWrapper<SaasArea> updateWrapper = null;
+
+		public Builder createQueryWrapper() {
+			queryWrapper = new LambdaQueryWrapper<SaasArea>();
+			return this;
+		}
+
+		public Builder createUpdateWrapper() {
+			updateWrapper = new LambdaUpdateWrapper<SaasArea>();
+			return this;
+		}
+
+		public Builder idEq(String id) {
+			if (StringUtil.isNotBlank(id)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasArea::getId, id);
+				} else {
+					queryWrapper.eq(SaasArea::getId, id);
+				}
+			}
+			return this;
+		}
+
+		public Builder groupCodeEq(String groupCode) {
+			if (StringUtil.isNotBlank(groupCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasArea::getGroupCode, groupCode);
+				} else {
+					queryWrapper.eq(SaasArea::getGroupCode, groupCode);
+				}
+			}
+			return this;
+		}
+		
+		public Builder parentIdEq(String parentId) {
+			if (StringUtil.isNotBlank(parentId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasArea::getParentId, parentId);
+				} else {
+					queryWrapper.eq(SaasArea::getParentId, parentId);
+				}
+			}
+			return this;
+		}
+		
+		public Builder parentIdIsNull() {
+			if (updateWrapper != null) {
+				updateWrapper.and(wrapper -> wrapper
+						.isNull(SaasArea::getParentId)
+						.or()
+						.eq(SaasArea::getParentId, ""));
+			} else {
+				queryWrapper.and(wrapper -> wrapper
+						.isNull(SaasArea::getParentId)
+						.or()
+						.eq(SaasArea::getParentId, ""));
+			}
+			return this;
+		}
+
+		public Builder areaCodeEq(String areaCode) {
+			if (StringUtil.isNotBlank(areaCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasArea::getAreaCode, areaCode);
+				} else {
+					queryWrapper.eq(SaasArea::getAreaCode, areaCode);
+				}
+			}
+			return this;
+		}
+
+		public Builder areaNameEq(String areaName) {
+			if (StringUtil.isNotBlank(areaName)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasArea::getAreaName, areaName);
+				} else {
+					queryWrapper.eq(SaasArea::getAreaName, areaName);
+				}
+			}
+			return this;
+		}
+		
+		public Builder areaNameLike(String areaName) {
+			if (StringUtil.isNotBlank(areaName)) {
+				if (updateWrapper != null) {
+					updateWrapper.like(SaasArea::getAreaName, areaName);
+				} else {
+					queryWrapper.like(SaasArea::getAreaName, areaName);
+				}
+			}
+			return this;
+		}
+
+		public Builder areaTypeEq(String areaType) {
+			if (StringUtil.isNotBlank(areaType)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasArea::getAreaType, areaType);
+				} else {
+					queryWrapper.eq(SaasArea::getAreaType, areaType);
+				}
+			}
+			return this;
+		}
+
+		public Builder createTimeEq(Date createTime) {
+			if (null != createTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasArea::getCreateTime, createTime);
+				} else {
+					queryWrapper.eq(SaasArea::getCreateTime, createTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateTimeEq(Date updateTime) {
+			if (null != updateTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasArea::getUpdateTime, updateTime);
+				} else {
+					queryWrapper.eq(SaasArea::getUpdateTime, updateTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateUserEq(String updateUser) {
+			if (StringUtil.isNotBlank(updateUser)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasArea::getUpdateUser, updateUser);
+				} else {
+					queryWrapper.eq(SaasArea::getUpdateUser, updateUser);
+				}
+			}
+			return this;
+		}
+
+		public Builder remarkEq(String remark) {
+			if (StringUtil.isNotBlank(remark)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasArea::getRemark, remark);
+				} else {
+					queryWrapper.eq(SaasArea::getRemark, remark);
+				}
+			}
+			return this;
+		}
+
+		public LambdaQueryWrapper<SaasArea> builderQueryWrapper() {
+			return queryWrapper;
+		}
+
+		public LambdaUpdateWrapper<SaasArea> builderUpdateWrapper() {
+			return updateWrapper;
+		}
+	}
+}

+ 213 - 0
saas-account/src/main/java/com/persagy/person/pojo/dto/SaasFunction.java

@@ -0,0 +1,213 @@
+package com.persagy.person.pojo.dto;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.persagy.common.annotation.IdGeneratorPrefix;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseEntity;
+import com.persagy.common.utils.StringUtil;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 功能信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode(callSuper = false)
+@TableName("saas_function")
+@IdGeneratorPrefix(SaasCommonConstant.SAAS_FUNCTION_ID_PREFIX)
+public class SaasFunction extends BaseEntity<SaasFunction> {
+	private static final long serialVersionUID = 7760376088679533302L;
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String menuId; // 菜单ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String funCode; // 功能编码
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String funName; // 功能名称
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String funUrl;	//功能URL
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Integer funSort; // 功能顺序
+
+	@TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date createTime; // 创建时间
+
+	@TableField(fill = FieldFill.INSERT_UPDATE, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date updateTime; // 更新时间
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String updateUser; // 最后一次操作者ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String remark; // 备注
+
+	@TableField(exist = false)
+	private String groupCode; // 集团编码
+	
+	public static class Builder {
+
+		private LambdaQueryWrapper<SaasFunction> queryWrapper = null;
+
+		private LambdaUpdateWrapper<SaasFunction> updateWrapper = null;
+
+		public Builder createQueryWrapper() {
+			queryWrapper = new LambdaQueryWrapper<SaasFunction>();
+			return this;
+		}
+
+		public Builder createUpdateWrapper() {
+			updateWrapper = new LambdaUpdateWrapper<SaasFunction>();
+			return this;
+		}
+
+		public Builder idEq(String id) {
+			if (StringUtil.isNotBlank(id)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasFunction::getId, id);
+				} else {
+					queryWrapper.eq(SaasFunction::getId, id);
+				}
+			}
+			return this;
+		}
+
+		public Builder menuIdEq(String menuId) {
+			if (StringUtil.isNotBlank(menuId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasFunction::getMenuId, menuId);
+				} else {
+					queryWrapper.eq(SaasFunction::getMenuId, menuId);
+				}
+			}
+			return this;
+		}
+
+		public Builder funCodeEq(String funCode) {
+			if (StringUtil.isNotBlank(funCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasFunction::getFunCode, funCode);
+				} else {
+					queryWrapper.eq(SaasFunction::getFunCode, funCode);
+				}
+			}
+			return this;
+		}
+
+		public Builder funNameEq(String funName) {
+			if (StringUtil.isNotBlank(funName)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasFunction::getFunName, funName);
+				} else {
+					queryWrapper.eq(SaasFunction::getFunName, funName);
+				}
+			}
+			return this;
+		}
+		
+		public Builder funNameLike(String funName) {
+			if (StringUtil.isNotBlank(funName)) {
+				if (updateWrapper != null) {
+					updateWrapper.like(SaasFunction::getFunName, funName);
+				} else {
+					queryWrapper.like(SaasFunction::getFunName, funName);
+				}
+			}
+			return this;
+		}
+		
+		public Builder funUrlEq(String funUrl) {
+			if (StringUtil.isNotBlank(funUrl)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasFunction::getFunUrl, funUrl);
+				} else {
+					queryWrapper.eq(SaasFunction::getFunUrl, funUrl);
+				}
+			}
+			return this;
+		}
+
+		public Builder funSortEq(Integer funSort) {
+			if (null != funSort) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasFunction::getFunSort, funSort);
+				} else {
+					queryWrapper.eq(SaasFunction::getFunSort, funSort);
+				}
+			}
+			return this;
+		}
+
+		public Builder createTimeEq(Date createTime) {
+			if (null != createTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasFunction::getCreateTime, createTime);
+				} else {
+					queryWrapper.eq(SaasFunction::getCreateTime, createTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateTimeEq(Date updateTime) {
+			if (null != updateTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasFunction::getUpdateTime, updateTime);
+				} else {
+					queryWrapper.eq(SaasFunction::getUpdateTime, updateTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateUserEq(String updateUser) {
+			if (StringUtil.isNotBlank(updateUser)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasFunction::getUpdateUser, updateUser);
+				} else {
+					queryWrapper.eq(SaasFunction::getUpdateUser, updateUser);
+				}
+			}
+			return this;
+		}
+
+		public Builder remarkEq(String remark) {
+			if (StringUtil.isNotBlank(remark)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasFunction::getRemark, remark);
+				} else {
+					queryWrapper.eq(SaasFunction::getRemark, remark);
+				}
+			}
+			return this;
+		}
+
+		public LambdaQueryWrapper<SaasFunction> builderQueryWrapper() {
+			return queryWrapper;
+		}
+
+		public LambdaUpdateWrapper<SaasFunction> builderUpdateWrapper() {
+			return updateWrapper;
+		}
+	}
+}

+ 248 - 0
saas-account/src/main/java/com/persagy/person/pojo/dto/SaasGroup.java

@@ -0,0 +1,248 @@
+package com.persagy.person.pojo.dto;
+
+import java.util.Date;
+import java.util.List;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.persagy.common.utils.StringUtil;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 集团信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode(callSuper = false)
+@TableName("saas_group")
+public class SaasGroup extends Model<SaasGroup> {
+	private static final long serialVersionUID = -8224369302252013334L;
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupCode; // 集团编码
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupName; // 集团名称,业务保证唯一性
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupIcon; // 集团图标
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupDesc; // 集团描述
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String deployModel; // 集团部署方式,0-公有云,1-私有云
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String syncState; // 数据同步状态,0-数据同步失败,1-数据同步成功
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date syncTime; // 上次数据同步时间
+
+	@TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date createTime; // 创建时间
+
+	@TableField(fill = FieldFill.INSERT_UPDATE, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date updateTime; // 更新时间
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String updateUser; // 最后一次操作者ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String remark; // 备注
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Integer valid; // 0-不可用,1-可用
+
+	@TableField(exist = false)
+	private List<SaasProject> projects;		//项目集合
+	
+	@TableField(exist = false)
+	private List<SaasArea> areas;	//集团下顶层区域
+	
+	@TableField(exist = false)
+	private String type;	//类型 create-创建,update-更新
+	
+	public static class Builder {
+
+		private LambdaQueryWrapper<SaasGroup> queryWrapper = null;
+
+		private LambdaUpdateWrapper<SaasGroup> updateWrapper = null;
+
+		public Builder createQueryWrapper() {
+			queryWrapper = new LambdaQueryWrapper<SaasGroup>();
+			return this;
+		}
+
+		public Builder createUpdateWrapper() {
+			updateWrapper = new LambdaUpdateWrapper<SaasGroup>();
+			return this;
+		}
+
+		public Builder groupCodeEq(String groupCode) {
+			if (StringUtil.isNotBlank(groupCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getGroupCode, groupCode);
+				} else {
+					queryWrapper.eq(SaasGroup::getGroupCode, groupCode);
+				}
+			}
+			return this;
+		}
+
+		public Builder groupNameEq(String groupName) {
+			if (StringUtil.isNotBlank(groupName)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getGroupName, groupName);
+				} else {
+					queryWrapper.eq(SaasGroup::getGroupName, groupName);
+				}
+			}
+			return this;
+		}
+		
+		public Builder groupNameLike(String groupName) {
+			if (StringUtil.isNotBlank(groupName)) {
+				if (updateWrapper != null) {
+					updateWrapper.like(SaasGroup::getGroupName, groupName);
+				} else {
+					queryWrapper.like(SaasGroup::getGroupName, groupName);
+				}
+			}
+			return this;
+		}
+
+		public Builder groupIconEq(String groupIcon) {
+			if (StringUtil.isNotBlank(groupIcon)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getGroupIcon, groupIcon);
+				} else {
+					queryWrapper.eq(SaasGroup::getGroupIcon, groupIcon);
+				}
+			}
+			return this;
+		}
+
+		public Builder groupDescEq(String groupDesc) {
+			if (StringUtil.isNotBlank(groupDesc)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getGroupDesc, groupDesc);
+				} else {
+					queryWrapper.eq(SaasGroup::getGroupDesc, groupDesc);
+				}
+			}
+			return this;
+		}
+
+		public Builder deployModelEq(String deployModel) {
+			if (StringUtil.isNotBlank(deployModel)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getDeployModel, deployModel);
+				} else {
+					queryWrapper.eq(SaasGroup::getDeployModel, deployModel);
+				}
+			}
+			return this;
+		}
+
+		public Builder syncStateEq(String syncState) {
+			if (StringUtil.isNotBlank(syncState)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getSyncState, syncState);
+				} else {
+					queryWrapper.eq(SaasGroup::getSyncState, syncState);
+				}
+			}
+			return this;
+		}
+
+		public Builder syncTimeEq(Date syncTime) {
+			if (null != syncTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getSyncTime, syncTime);
+				} else {
+					queryWrapper.eq(SaasGroup::getSyncTime, syncTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder createTimeEq(Date createTime) {
+			if (null != createTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getCreateTime, createTime);
+				} else {
+					queryWrapper.eq(SaasGroup::getCreateTime, createTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateTimeEq(Date updateTime) {
+			if (null != updateTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getUpdateTime, updateTime);
+				} else {
+					queryWrapper.eq(SaasGroup::getUpdateTime, updateTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateUserEq(String updateUser) {
+			if (StringUtil.isNotBlank(updateUser)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getUpdateUser, updateUser);
+				} else {
+					queryWrapper.eq(SaasGroup::getUpdateUser, updateUser);
+				}
+			}
+			return this;
+		}
+
+		public Builder remarkEq(String remark) {
+			if (StringUtil.isNotBlank(remark)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getRemark, remark);
+				} else {
+					queryWrapper.eq(SaasGroup::getRemark, remark);
+				}
+			}
+			return this;
+		}
+
+		public Builder validEq(Integer valid) {
+			if (null != valid) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasGroup::getValid, valid);
+				} else {
+					queryWrapper.eq(SaasGroup::getValid, valid);
+				}
+			}
+			return this;
+		}
+
+		public LambdaQueryWrapper<SaasGroup> builderQueryWrapper() {
+			return queryWrapper;
+		}
+
+		public LambdaUpdateWrapper<SaasGroup> builderUpdateWrapper() {
+			return updateWrapper;
+		}
+	}
+}

+ 274 - 0
saas-account/src/main/java/com/persagy/person/pojo/dto/SaasMenu.java

@@ -0,0 +1,274 @@
+package com.persagy.person.pojo.dto;
+
+import java.util.Date;
+import java.util.List;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.persagy.common.annotation.IdGeneratorPrefix;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseEntity;
+import com.persagy.common.utils.StringUtil;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 菜单信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode(callSuper = false)
+@TableName("saas_menu")
+@IdGeneratorPrefix(SaasCommonConstant.SAAS_MENU_ID_PREFIX)
+public class SaasMenu extends BaseEntity<SaasMenu> {
+	private static final long serialVersionUID = -4911716291586261567L;
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String parentId; // 上级菜单ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String appId; // 应用ID, PC-电脑端,APP-手机端
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String menuCode; // 菜单编码
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String menuName; // 菜单名称
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String menuUrl; // 菜单URL
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String urlType;	//URL类型,0-相对路径,1-绝对路径
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String menuIcon; // 菜单图标
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Integer menuSort; // 菜单顺序
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String menuType;	//菜单类型,0-系统菜单,1-标准业务菜单,2-IBMS菜单,3-APP菜单
+
+	@TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date createTime; // 创建时间
+
+	@TableField(fill = FieldFill.INSERT_UPDATE, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date updateTime; // 更新时间
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String updateUser; // 最后一次操作者ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String remark; // 备注
+
+	@TableField(exist = false)
+	private String groupCode; // 集团编码
+	
+	@TableField(exist = false)
+	private String accountId; // 账号ID
+	
+	@TableField(exist = false)
+	private String roleId;	//角色ID
+	
+	@TableField(exist = false)
+	private String menuId;	//菜单ID
+	
+	@TableField(exist = false)
+	private List<SaasMenu> childrens;	//下级菜单
+	
+	@TableField(exist = false)
+	private List<SaasFunction> functions;	//对应功能点集合
+	
+	public static class Builder {
+
+		private LambdaQueryWrapper<SaasMenu> queryWrapper = null;
+
+		private LambdaUpdateWrapper<SaasMenu> updateWrapper = null;
+
+		public Builder createQueryWrapper() {
+			queryWrapper = new LambdaQueryWrapper<SaasMenu>();
+			return this;
+		}
+
+		public Builder createUpdateWrapper() {
+			updateWrapper = new LambdaUpdateWrapper<SaasMenu>();
+			return this;
+		}
+
+		public Builder idEq(String id) {
+			if (StringUtil.isNotBlank(id)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getId, id);
+				} else {
+					queryWrapper.eq(SaasMenu::getId, id);
+				}
+			}
+			return this;
+		}
+
+		public Builder parentIdEq(String parentId) {
+			if (StringUtil.isNotBlank(parentId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getParentId, parentId);
+				} else {
+					queryWrapper.eq(SaasMenu::getParentId, parentId);
+				}
+			}
+			return this;
+		}
+
+		public Builder appIdEq(String appId) {
+			if (StringUtil.isNotBlank(appId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getAppId, appId);
+				} else {
+					queryWrapper.eq(SaasMenu::getAppId, appId);
+				}
+			}
+			return this;
+		}
+
+		public Builder menuCodeEq(String menuCode) {
+			if (StringUtil.isNotBlank(menuCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getMenuCode, menuCode);
+				} else {
+					queryWrapper.eq(SaasMenu::getMenuCode, menuCode);
+				}
+			}
+			return this;
+		}
+
+		public Builder menuNameEq(String menuName) {
+			if (StringUtil.isNotBlank(menuName)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getMenuName, menuName);
+				} else {
+					queryWrapper.eq(SaasMenu::getMenuName, menuName);
+				}
+			}
+			return this;
+		}
+
+		public Builder menuUrlEq(String menuUrl) {
+			if (StringUtil.isNotBlank(menuUrl)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getMenuUrl, menuUrl);
+				} else {
+					queryWrapper.eq(SaasMenu::getMenuUrl, menuUrl);
+				}
+			}
+			return this;
+		}
+		
+		public Builder urlTypeEq(String urlType) {
+			if (StringUtil.isNotBlank(urlType)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getUrlType, urlType);
+				} else {
+					queryWrapper.eq(SaasMenu::getUrlType, urlType);
+				}
+			}
+			return this;
+		}
+
+		public Builder menuIconEq(String menuIcon) {
+			if (StringUtil.isNotBlank(menuIcon)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getMenuIcon, menuIcon);
+				} else {
+					queryWrapper.eq(SaasMenu::getMenuIcon, menuIcon);
+				}
+			}
+			return this;
+		}
+
+		public Builder menuSortEq(Integer menuSort) {
+			if (null != menuSort) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getMenuSort, menuSort);
+				} else {
+					queryWrapper.eq(SaasMenu::getMenuSort, menuSort);
+				}
+			}
+			return this;
+		}
+		
+		public Builder menuTypeEq(String menuType) {
+			if (StringUtil.isNotBlank(menuType)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getMenuType, menuType);
+				} else {
+					queryWrapper.eq(SaasMenu::getMenuType, menuType);
+				}
+			}
+			return this;
+		}
+
+		public Builder createTimeEq(Date createTime) {
+			if (null != createTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getCreateTime, createTime);
+				} else {
+					queryWrapper.eq(SaasMenu::getCreateTime, createTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateTimeEq(Date updateTime) {
+			if (null != updateTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getUpdateTime, updateTime);
+				} else {
+					queryWrapper.eq(SaasMenu::getUpdateTime, updateTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateUserEq(String updateUser) {
+			if (StringUtil.isNotBlank(updateUser)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getUpdateUser, updateUser);
+				} else {
+					queryWrapper.eq(SaasMenu::getUpdateUser, updateUser);
+				}
+			}
+			return this;
+		}
+
+		public Builder remarkEq(String remark) {
+			if (StringUtil.isNotBlank(remark)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasMenu::getRemark, remark);
+				} else {
+					queryWrapper.eq(SaasMenu::getRemark, remark);
+				}
+			}
+			return this;
+		}
+
+		public LambdaQueryWrapper<SaasMenu> builderQueryWrapper() {
+			return queryWrapper;
+		}
+
+		public LambdaUpdateWrapper<SaasMenu> builderUpdateWrapper() {
+			return updateWrapper;
+		}
+	}
+}

+ 327 - 0
saas-account/src/main/java/com/persagy/person/pojo/dto/SaasProject.java

@@ -0,0 +1,327 @@
+package com.persagy.person.pojo.dto;
+
+import java.util.Date;
+import java.util.Set;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.persagy.common.annotation.IdGeneratorPrefix;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseEntity;
+import com.persagy.common.utils.StringUtil;
+
+import cn.hutool.core.collection.CollectionUtil;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode(callSuper = false)
+@TableName("saas_project")
+@IdGeneratorPrefix(SaasCommonConstant.SAAS_PROJECT_ID_PREFIX)
+public class SaasProject extends BaseEntity<SaasProject> {
+	private static final long serialVersionUID = -4224325454752727633L;
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupCode; // 集团编码
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String projectId; // 项目ID,与集团编码联合唯一,业务保证
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String areaId; // 项目所属区域,必须为最底层的区域
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String projectLocalId; // 项目本地编码
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String projectName; // 项目名称
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String provinceCode;	//项目所在省
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String cityCode;	//项目所在市
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String zoneCode;	//项目所在区
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String location;	//项目详细地址
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date openTime;	//项目开业时间
+	
+	@TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date createTime; 	// 创建时间
+
+	@TableField(fill = FieldFill.INSERT_UPDATE, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date updateTime; 	// 更新时间
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String updateUser; 	// 最后一次操作者ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String remark; 		// 备注
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Integer valid; 		// 0-不可用,1-可用
+
+	@TableField(exist = false)
+	private Set<String> projectIds; 	// 项目ID集合
+	
+	@TableField(exist = false)
+	private String accountId; 	// 当前账号ID
+	
+	@TableField(exist = false)
+	private String areaName; // 区域名称
+	
+	public static class Builder {
+
+		private LambdaQueryWrapper<SaasProject> queryWrapper = null;
+
+		private LambdaUpdateWrapper<SaasProject> updateWrapper = null;
+
+		public Builder createQueryWrapper() {
+			queryWrapper = new LambdaQueryWrapper<SaasProject>();
+			return this;
+		}
+
+		public Builder createUpdateWrapper() {
+			updateWrapper = new LambdaUpdateWrapper<SaasProject>();
+			return this;
+		}
+
+		public Builder idEq(String id) {
+			if (StringUtil.isNotBlank(id)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getId, id);
+				} else {
+					queryWrapper.eq(SaasProject::getId, id);
+				}
+			}
+			return this;
+		}
+
+		public Builder groupCodeEq(String groupCode) {
+			if (StringUtil.isNotBlank(groupCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getGroupCode, groupCode);
+				} else {
+					queryWrapper.eq(SaasProject::getGroupCode, groupCode);
+				}
+			}
+			return this;
+		}
+
+		public Builder projectIdEq(String projectId) {
+			if (StringUtil.isNotBlank(projectId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getProjectId, projectId);
+				} else {
+					queryWrapper.eq(SaasProject::getProjectId, projectId);
+				}
+			}
+			return this;
+		}
+		
+		public Builder projectIdIn(Set<String> projectIds) {
+			if (CollectionUtil.isNotEmpty(projectIds)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getProjectId, projectIds);
+				} else {
+					queryWrapper.eq(SaasProject::getProjectId, projectIds);
+				}
+			}
+			return this;
+		}
+
+		public Builder areaIdEq(String areaId) {
+			if (StringUtil.isNotBlank(areaId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getAreaId, areaId);
+				} else {
+					queryWrapper.eq(SaasProject::getAreaId, areaId);
+				}
+			}
+			return this;
+		}
+
+		public Builder projectLocalIdEq(String projectLocalId) {
+			if (StringUtil.isNotBlank(projectLocalId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getProjectLocalId, projectLocalId);
+				} else {
+					queryWrapper.eq(SaasProject::getProjectLocalId, projectLocalId);
+				}
+			}
+			return this;
+		}
+
+		public Builder projectNameEq(String projectName) {
+			if (StringUtil.isNotBlank(projectName)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getProjectName, projectName);
+				} else {
+					queryWrapper.eq(SaasProject::getProjectName, projectName);
+				}
+			}
+			return this;
+		}
+		
+		public Builder projectNameLike(String projectName) {
+			if (StringUtil.isNotBlank(projectName)) {
+				if (updateWrapper != null) {
+					updateWrapper.like(SaasProject::getProjectName, projectName);
+				} else {
+					queryWrapper.like(SaasProject::getProjectName, projectName);
+				}
+			}
+			return this;
+		}
+
+		public Builder provinceCodeEq(String provinceCode) {
+			if (StringUtil.isNotBlank(provinceCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getProvinceCode, provinceCode);
+				} else {
+					queryWrapper.eq(SaasProject::getProvinceCode, provinceCode);
+				}
+			}
+			return this;
+		}
+		
+		public Builder cityCodeEq(String cityCode) {
+			if (StringUtil.isNotBlank(cityCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getCityCode, cityCode);
+				} else {
+					queryWrapper.eq(SaasProject::getCityCode, cityCode);
+				}
+			}
+			return this;
+		}
+		
+		public Builder zoneCodeEq(String zoneCode) {
+			if (StringUtil.isNotBlank(zoneCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getZoneCode, zoneCode);
+				} else {
+					queryWrapper.eq(SaasProject::getZoneCode, zoneCode);
+				}
+			}
+			return this;
+		}
+		
+		public Builder openTimeEq(Date openTime) {
+			if (null != openTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getOpenTime, openTime);
+				} else {
+					queryWrapper.eq(SaasProject::getOpenTime, openTime);
+				}
+			}
+			return this;
+		}
+		
+		public Builder openTimeGe(Date openTime) {
+			if (null != openTime) {
+				if (updateWrapper != null) {
+					updateWrapper.ge(SaasProject::getOpenTime, openTime);
+				} else {
+					queryWrapper.ge(SaasProject::getOpenTime, openTime);
+				}
+			}
+			return this;
+		}
+		
+		public Builder createTimeEq(Date createTime) {
+			if (null != createTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getCreateTime, createTime);
+				} else {
+					queryWrapper.eq(SaasProject::getCreateTime, createTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateTimeEq(Date updateTime) {
+			if (null != updateTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getUpdateTime, updateTime);
+				} else {
+					queryWrapper.eq(SaasProject::getUpdateTime, updateTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateUserEq(String updateUser) {
+			if (StringUtil.isNotBlank(updateUser)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getUpdateUser, updateUser);
+				} else {
+					queryWrapper.eq(SaasProject::getUpdateUser, updateUser);
+				}
+			}
+			return this;
+		}
+
+		public Builder remarkEq(String remark) {
+			if (StringUtil.isNotBlank(remark)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getRemark, remark);
+				} else {
+					queryWrapper.eq(SaasProject::getRemark, remark);
+				}
+			}
+			return this;
+		}
+
+		public Builder validEq(Integer valid) {
+			if (null != valid) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasProject::getValid, valid);
+				} else {
+					queryWrapper.eq(SaasProject::getValid, valid);
+				}
+			}
+			return this;
+		}
+		
+		public Builder last(String lastSql) {
+			if (StringUtil.isNotBlank(lastSql)) {
+				if (updateWrapper != null) {
+					updateWrapper.last(lastSql);
+				} else {
+					queryWrapper.last(lastSql);
+				}
+			}
+			return this;
+		}
+
+		public LambdaQueryWrapper<SaasProject> builderQueryWrapper() {
+			return queryWrapper;
+		}
+
+		public LambdaUpdateWrapper<SaasProject> builderUpdateWrapper() {
+			return updateWrapper;
+		}
+	}
+}

+ 229 - 0
saas-account/src/main/java/com/persagy/person/pojo/dto/SaasRole.java

@@ -0,0 +1,229 @@
+package com.persagy.person.pojo.dto;
+
+import java.util.Date;
+import java.util.Set;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.persagy.common.annotation.IdGeneratorPrefix;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseEntity;
+import com.persagy.common.utils.StringUtil;
+
+import cn.hutool.core.collection.CollectionUtil;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode(callSuper = false)
+@TableName("saas_role")
+@IdGeneratorPrefix(SaasCommonConstant.SAAS_ROLE_ID_PREFIX)
+public class SaasRole extends BaseEntity<SaasRole> {
+	private static final long serialVersionUID = 7817018825667753153L;
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupCode; // 集团编码
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String roleCode; // 角色编码
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String roleName; // 角色名称
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String roleType; // 角色类型,0-系统角色,1-业务角色, 2-业务超管默认角色
+	
+	@TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date createTime; // 创建时间
+
+	@TableField(fill = FieldFill.INSERT_UPDATE, updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Date updateTime; // 更新时间
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String updateUser; // 最后一次操作者ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String remark; // 备注
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private Integer valid; // 0-不可用,1-可用
+	
+	@TableField(exist = false)
+	private Integer countMenu;	//统计出菜单数量
+	
+	@TableField(exist = false)
+	private Integer countFunction;	//统计出下级功能点数量
+
+	public static class Builder {
+
+		private LambdaQueryWrapper<SaasRole> queryWrapper = null;
+
+		private LambdaUpdateWrapper<SaasRole> updateWrapper = null;
+
+		public Builder createQueryWrapper() {
+			queryWrapper = new LambdaQueryWrapper<SaasRole>();
+			return this;
+		}
+
+		public Builder createUpdateWrapper() {
+			updateWrapper = new LambdaUpdateWrapper<SaasRole>();
+			return this;
+		}
+
+		public Builder idEq(String id) {
+			if (StringUtil.isNotBlank(id)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRole::getId, id);
+				} else {
+					queryWrapper.eq(SaasRole::getId, id);
+				}
+			}
+			return this;
+		}
+		
+		public Builder idIn(Set<String> ids) {
+			if (CollectionUtil.isNotEmpty(ids)) {
+				if (updateWrapper != null) {
+					updateWrapper.in(SaasRole::getId, ids);
+				} else {
+					queryWrapper.in(SaasRole::getId, ids);
+				}
+			}
+			return this;
+		}
+
+		public Builder groupCodeEq(String groupCode) {
+			if (StringUtil.isNotBlank(groupCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRole::getGroupCode, groupCode);
+				} else {
+					queryWrapper.eq(SaasRole::getGroupCode, groupCode);
+				}
+			}
+			return this;
+		}
+		
+		public Builder roleCodeEq(String roleCode) {
+			if (StringUtil.isNotBlank(roleCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRole::getRoleCode, roleCode);
+				} else {
+					queryWrapper.eq(SaasRole::getRoleCode, roleCode);
+				}
+			}
+			return this;
+		}
+
+		public Builder roleNameEq(String roleName) {
+			if (StringUtil.isNotBlank(roleName)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRole::getRoleName, roleName);
+				} else {
+					queryWrapper.eq(SaasRole::getRoleName, roleName);
+				}
+			}
+			return this;
+		}
+		
+		public Builder roleNameLike(String roleName) {
+			if (StringUtil.isNotBlank(roleName)) {
+				if (updateWrapper != null) {
+					updateWrapper.like(SaasRole::getRoleName, roleName);
+				} else {
+					queryWrapper.like(SaasRole::getRoleName, roleName);
+				}
+			}
+			return this;
+		}
+		
+		public Builder roleTypeEq(String roleType) {
+			if (StringUtil.isNotBlank(roleType)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRole::getRoleType, roleType);
+				} else {
+					queryWrapper.eq(SaasRole::getRoleType, roleType);
+				}
+			}
+			return this;
+		}
+
+		public Builder createTimeEq(Date createTime) {
+			if (null != createTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRole::getCreateTime, createTime);
+				} else {
+					queryWrapper.eq(SaasRole::getCreateTime, createTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateTimeEq(Date updateTime) {
+			if (null != updateTime) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRole::getUpdateTime, updateTime);
+				} else {
+					queryWrapper.eq(SaasRole::getUpdateTime, updateTime);
+				}
+			}
+			return this;
+		}
+
+		public Builder updateUserEq(String updateUser) {
+			if (StringUtil.isNotBlank(updateUser)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRole::getUpdateUser, updateUser);
+				} else {
+					queryWrapper.eq(SaasRole::getUpdateUser, updateUser);
+				}
+			}
+			return this;
+		}
+
+		public Builder remarkEq(String remark) {
+			if (StringUtil.isNotBlank(remark)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRole::getRemark, remark);
+				} else {
+					queryWrapper.eq(SaasRole::getRemark, remark);
+				}
+			}
+			return this;
+		}
+
+		public Builder validEq(Integer valid) {
+			if (null != valid) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRole::getValid, valid);
+				} else {
+					queryWrapper.eq(SaasRole::getValid, valid);
+				}
+			}
+			return this;
+		}
+
+		public LambdaQueryWrapper<SaasRole> builderQueryWrapper() {
+			return queryWrapper;
+		}
+
+		public LambdaUpdateWrapper<SaasRole> builderUpdateWrapper() {
+			return updateWrapper;
+		}
+	}
+}

+ 112 - 0
saas-account/src/main/java/com/persagy/person/pojo/dto/SaasRoleMenu.java

@@ -0,0 +1,112 @@
+package com.persagy.person.pojo.dto;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.persagy.common.utils.StringUtil;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色-菜单功能关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode(callSuper = false)
+@TableName("saas_role_menu")
+public class SaasRoleMenu extends Model<SaasRoleMenu> {
+	private static final long serialVersionUID = 7777627780073191075L;
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String groupCode; // 集团编码
+	
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String roleId; 	// 角色ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String menuId; 	// 菜单ID
+
+	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	private String functionId; // 功能ID
+
+	public static class Builder {
+
+		private LambdaQueryWrapper<SaasRoleMenu> queryWrapper = null;
+
+		private LambdaUpdateWrapper<SaasRoleMenu> updateWrapper = null;
+
+		public Builder createQueryWrapper() {
+			queryWrapper = new LambdaQueryWrapper<SaasRoleMenu>();
+			return this;
+		}
+
+		public Builder createUpdateWrapper() {
+			updateWrapper = new LambdaUpdateWrapper<SaasRoleMenu>();
+			return this;
+		}
+
+		public Builder groupCodeEq(String groupCode) {
+			if (StringUtil.isNotBlank(groupCode)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRoleMenu::getGroupCode, groupCode);
+				} else {
+					queryWrapper.eq(SaasRoleMenu::getGroupCode, groupCode);
+				}
+			}
+			return this;
+		}
+		
+		public Builder roleIdEq(String roleId) {
+			if (StringUtil.isNotBlank(roleId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRoleMenu::getRoleId, roleId);
+				} else {
+					queryWrapper.eq(SaasRoleMenu::getRoleId, roleId);
+				}
+			}
+			return this;
+		}
+
+		public Builder menuIdEq(String menuId) {
+			if (StringUtil.isNotBlank(menuId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRoleMenu::getMenuId, menuId);
+				} else {
+					queryWrapper.eq(SaasRoleMenu::getMenuId, menuId);
+				}
+			}
+			return this;
+		}
+
+		public Builder functionIdEq(String functionId) {
+			if (StringUtil.isNotBlank(functionId)) {
+				if (updateWrapper != null) {
+					updateWrapper.eq(SaasRoleMenu::getFunctionId, functionId);
+				} else {
+					queryWrapper.eq(SaasRoleMenu::getFunctionId, functionId);
+				}
+			}
+			return this;
+		}
+
+		public LambdaQueryWrapper<SaasRoleMenu> builderQueryWrapper() {
+			return queryWrapper;
+		}
+
+		public LambdaUpdateWrapper<SaasRoleMenu> builderUpdateWrapper() {
+			return updateWrapper;
+		}
+	}
+}

+ 28 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/BaseGroupVO.java

@@ -0,0 +1,28 @@
+package com.persagy.person.pojo.vo;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 集团
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class BaseGroupVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "集团编码,作为SQL条件", required = true, example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+}

+ 29 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/BaseUserVO.java

@@ -0,0 +1,29 @@
+package com.persagy.person.pojo.vo;
+
+import javax.validation.constraints.NotBlank;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 集团
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class BaseUserVO {
+
+	@NotBlank(message = "账号ID,不可为空")
+	@ApiModelProperty(value = "账号ID", required = true, example = "RY56122123152")
+	private String accountId; 	// 当前账号ID
+	
+}

+ 98 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountCreateVO.java

@@ -0,0 +1,98 @@
+package com.persagy.person.pojo.vo.account;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.person.pojo.vo.auth.SaasAccountRoleVO;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountCreateVO {
+
+	@ApiModelProperty(value = "主键ID,更新时不可为空", example = "123456adzxzc")
+	private String accountId; 	// 当前账号ID
+	
+	@ApiModelProperty(value = "关联类型,0-主岗,1-副岗,2-业务超管默认角色", example = "0")
+	private String casType; 	// 关联类型,0-主岗,1-副岗,2-业务超管默认角色,这里关联类型会直接插入数据库中,不做为重置的条件
+	
+	@ApiModelProperty(value = "主键ID,更新时不可为空", example = "123456adzxzc")
+	private List<SaasAccountRoleVO> roles; 	// 账号关联的角色ID集合
+	
+	//@NotBlank(message = "集团编码,不可为空")
+	@ApiModelProperty(value = "集团编码,作为SQL条件", required = true, example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@NotBlank(message = "应用ID,不可为空")
+	@ApiModelProperty(value = "应用ID, PC-电脑端,APP-手机应用端", example = "PC", required = true)
+    private String appId;
+	
+	@NotBlank(message = "登录用户名,不可为空")
+	@ApiModelProperty(value = "登录用户名", example = "zhangsan", required = true)
+	private String username; // 登录用户名
+	
+	//@NotBlank(message = "登录密码,不可为空")
+	@ApiModelProperty(value = "登录密码", example = "zhangsan", required = true)
+	private String password; // 登录密码
+
+	@ApiModelProperty(value = "手机号", example = "18888888888")
+	private String phoneNum; // 手机号
+	
+	@ApiModelProperty(value = "邮箱", example = "18888888888@163.com")
+	private String mail; // 邮箱
+	
+	@ApiModelProperty(value = "头像,图片URL", example = "http://127.0.0.1:9980/test.img")
+	private String headPortrait; // 头像,图片URL
+
+	@NotBlank(message = "账号类型,不可为空")
+	@ApiModelProperty(value = "账号类型, 0-超级管理员(所有集团),1-单集团管理员(单集团),2-普通账号", example = "0")
+	private String accountType;		//账号类型, 0-超级管理员(所有集团),1-单集团管理员(单集团),2-普通账号
+	
+	@NotBlank(message = "账号所属,不可为空")
+	@ApiModelProperty(value = "账号所属, 0-运维系统账号,1-业务账号", example = "0")
+	private String accountBelong;	//账号所属, 0-运维系统账号,1-业务账号
+	
+	//@NotBlank(message = "账号来源,不可为空")
+	@ApiModelProperty(value = "账号来源", example = "persagy", required = true)
+	private String accountSource = SaasCommonConstant.ACCOUNT_SOURCE_PERSAGE; // 账号来源
+
+	//@NotNull(message = "账号有效期的开始时间,不可为空")
+	@ApiModelProperty(value = "账号有效期的开始时间[时间戳:1615720476050]", example = "1615720476050")	
+	private Date validStartTime; // 账号有效期的开始时间
+	
+	//@NotNull(message = "账号有效期的结束时间,不可为空")
+	@ApiModelProperty(value = "账号有效期的结束时间[时间戳:1615720476050]", example = "1615720476050")
+	private Date validEndTime; 	// 账号有效期的结束时间
+
+	@NotBlank(message = "账号有效期,不可为空")
+	@ApiModelProperty(value = "账号有效期,0-期内有效,1-永久有效", example = "1",  required = true)
+	private String validLast;	//账号有效期,0-期内有效,1-永久有效
+	
+	@ApiModelProperty(value = "备注", example = "测试账号")
+	private String remark; 		// 备注
+	
+	//@NotBlank(message = "账号状态不可为空")
+	@ApiModelProperty(value = "是否可用,0-不可用,1-可用", example = "1")
+	private Integer valid; 		// 0-不可用,1-可用
+	
+	private boolean isVerify = true;		// 是否进行验证集团编码必填, true-验证,false-不验证
+
+}

+ 33 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountGroupVO.java

@@ -0,0 +1,33 @@
+package com.persagy.person.pojo.vo.account;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年4月7日:	下午3:53:19
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountGroupVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "集团编码,作为SQL条件", required = true, example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@ApiModelProperty(value = "账号密码", required = true, example = "741852963")
+	private String oldPassword; 	// 账号密码
+
+	@ApiModelProperty(value = "账号密码", required = true, example = "741852963")
+	private String newPassword; 	// 账号密码
+	
+}

+ 44 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountLoginVO.java

@@ -0,0 +1,44 @@
+package com.persagy.person.pojo.vo.account;
+
+import javax.validation.constraints.NotBlank;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountLoginVO {
+
+	//@NotBlank(message = "应用ID,不可为空")
+	@ApiModelProperty(value = "应用ID", example = "PC", required = true)
+	private String appId; // appId
+	
+	@NotBlank(message = "登录用户名,不可为空")
+	@ApiModelProperty(value = "登录用户名", example = "zhangsan", required = true)
+	private String username; // 登录用户名
+	
+	@NotBlank(message = "登录密码,不可为空")
+	@ApiModelProperty(value = "登录密码", example = "zhangsan", required = true)
+	private String password; // 登录密码
+
+	//@NotBlank(message = "手机号,不可为空")
+	@ApiModelProperty(value = "手机号", example = "WD")
+	private String phone; // 手机号
+	
+	@ApiModelProperty(value = "记住登录", example = "false")
+	private boolean remember = false; // 记住登录
+	
+}

+ 36 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountPageVO.java

@@ -0,0 +1,36 @@
+package com.persagy.person.pojo.vo.account;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountPageVO extends SaasAccountQueryVO {
+
+	@Min(value = 1, message = "分页页码,不可低于1")
+	@NotNull(message = "分页页码,不可为空")
+	@ApiModelProperty(value = "分页页码", example = "1", required = true)
+	private Integer page;
+
+	@Min(value = 1, message = "分页大小,不可低于1")
+	@NotNull(message = "分页大小,不可为空")
+	@ApiModelProperty(value = "分页大小", example = "10", required = true)
+	private Integer size;
+
+}

+ 39 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountQueryByNameVO.java

@@ -0,0 +1,39 @@
+package com.persagy.person.pojo.vo.account;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountQueryByNameVO  {
+
+    @NotBlank(message = "账号所属,不可为空")
+    @ApiModelProperty(value = "账号所属, 0-运维系统账号,1-业务账号", example = "0")
+    private String accountBelong;	//账号所属, 0-运维系统账号,1-业务账号
+
+	@NotBlank(message = "集团编码,不可为空")
+	@ApiModelProperty(value = "集团编码,作为SQL条件", example = "RC")
+	private String groupCode; 	// 所属集团编码
+
+    @NotBlank(message = "登录用户名,不可为空")
+	@ApiModelProperty(value = "登录用户名", example = "zhangsan")
+	private String username; // 登录用户名
+
+
+
+}

+ 66 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/account/SaasAccountQueryVO.java

@@ -0,0 +1,66 @@
+package com.persagy.person.pojo.vo.account;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountQueryVO {
+
+	//@NotBlank(message = "集团编码,不可为空")
+	@ApiModelProperty(value = "集团编码,作为SQL条件", example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@ApiModelProperty(value = "集团编码是否为空,true-是,默认此参数不生效", example = "false")
+	private Boolean groupIsNull; 	// 集团编码是否为空,true-是,默认此参数不生效
+	
+	@ApiModelProperty(value = "账号ID", example = "RY56122123152")
+	private String accountId; 	// 当前账号ID
+	
+	@ApiModelProperty(value = "账号类型, 0-超级管理员(所有集团),1-单集团管理员(单集团),2-普通账号", example = "0")
+	private String accountType;		//账号类型, 0-超级管理员(所有集团),1-单集团管理员(单集团),2-普通账号
+	
+	@ApiModelProperty(value = "账号所属, 0-运维系统账号,1-业务账号", example = "0")
+	private String accountBelong;	//账号所属, 0-运维系统账号,1-业务账号
+	
+	@ApiModelProperty(value = "应用ID, PC-电脑端,APP-手机应用端", example = "PC")
+    private String appId;
+	
+	@ApiModelProperty(value = "登录用户名", example = "zhangsan")
+	private String username; // 登录用户名
+
+	@ApiModelProperty(value = "邮箱号", example = "18888888888@163.com")
+	private String mail; 	// 邮箱号
+	
+	@ApiModelProperty(value = "手机号", example = "18888888888")
+	private String phoneNum; // 手机号
+
+	@ApiModelProperty(value = "账号来源", example = "WD")
+	private String accountSource; // 账号来源
+
+	@ApiModelProperty(value = "最后一次操作者ID", example = "zhangsan")
+	private String updateUser; 	// 最后一次操作者ID
+	
+	@ApiModelProperty(value = "是否显示roles,true-显示,默认false", example = "false")
+	private Boolean showRoles; 	// 是否显示roles,true-显示,默认false
+	
+	@ApiModelProperty(value = "是否显示集团信息,true-显示,默认false", example = "false")
+	private Boolean showGroup; 	// 是否显示集团信息,true-显示,默认false
+
+	@ApiModelProperty(value = "是否可用,0-不可用,1-可用", example = "1")
+	private Integer valid; 		// 0-不可用,1-可用
+
+}

+ 49 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/area/SaasAreaCreateVO.java

@@ -0,0 +1,49 @@
+package com.persagy.person.pojo.vo.area;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 区域信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAreaCreateVO extends BaseGroupModel {
+
+	@ApiModelProperty(value = "区域ID,更新时不可为空", example = "100101")
+	private String id; // 区域ID
+	
+	//@NotBlank(message = "上级区域ID,不可为空")
+	@ApiModelProperty(value = "上级区域ID", example = "100101")
+	private String parentId; // 上级区域ID
+
+	//@NotBlank(message = "区域编码,不可为空")
+	@ApiModelProperty(value = "区域编码", example = "100101")
+	private String areaCode; // 区域编码
+
+	@NotBlank(message = "区域名称,不可为空")
+	@ApiModelProperty(value = "区域名称", example = "测试区域")
+	private String areaName; // 区域名称
+
+	@NotBlank(message = "区域类别,不可为空")
+	@ApiModelProperty(value = "区域类别,0-非最底层区域,1-最底层区域", example = "100101")
+	private String areaType; // 区域类别,0-非最底层区域,1-最底层区域
+
+	@ApiModelProperty(value = "备注", example = "测试区域")
+	private String remark; // 备注
+	
+}

+ 31 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/area/SaasAreaDeleteVO.java

@@ -0,0 +1,31 @@
+package com.persagy.person.pojo.vo.area;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 区域信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAreaDeleteVO extends BaseGroupModel {
+
+	@NotBlank(message = "区域ID,不可为空")
+	@ApiModelProperty(value = "区域ID", example = "100101")
+	private String id; 		// 区域ID
+	
+}

+ 46 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/area/SaasAreaQueryVO.java

@@ -0,0 +1,46 @@
+package com.persagy.person.pojo.vo.area;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 区域信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAreaQueryVO extends BaseGroupModel {
+
+	@ApiModelProperty(value = "区域ID", example = "100101")
+	private String id; // 区域ID
+	
+	@ApiModelProperty(value = "上级区域ID", example = "100101")
+	private String parentId; // 上级区域ID
+
+	@ApiModelProperty(value = "区域编码", example = "100101")
+	private String areaCode; // 区域编码
+
+	@ApiModelProperty(value = "区域名称", example = "测试区域")
+	private String areaName; // 区域名称
+
+	@ApiModelProperty(value = "区域类别,0-非最底层区域,1-最底层区域", example = "100101")
+	private String areaType; // 区域类别,0-非最底层区域,1-最底层区域
+
+	@ApiModelProperty(value = "最后一次操作者ID", example = "100101")
+	private String updateUser; // 最后一次操作者ID
+	
+	@ApiModelProperty(value = "是否统计出该层区域及其下级所包含的所有项目数量,默认false-不统计", example = "false")
+	private boolean isTotal = false; 	// 是否统计出该层区域及其下级所包含的所有项目数量
+
+}

+ 39 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/AccountAreaProjectResetVO.java

@@ -0,0 +1,39 @@
+package com.persagy.person.pojo.vo.auth;
+
+import java.util.List;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色-菜单功能关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class AccountAreaProjectResetVO extends BaseUserModel {
+
+	//@NotEmpty(message = "区域集合,不可为空")
+	@ApiModelProperty(value = "区域集合,作为SQL条件", required = true, example = "RC")
+	private List<AccountAreaResetVO> areas; 	// 区域集合
+	
+	@Valid
+	@NotEmpty(message = "项目集合,不可为空")
+	@ApiModelProperty(value = "项目集合,作为SQL条件", required = true, example = "RC")
+	private List<AccountProjectResetVO> projects; 	// 项目集合
+	
+}

+ 33 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/AccountAreaResetVO.java

@@ -0,0 +1,33 @@
+package com.persagy.person.pojo.vo.auth;
+
+import javax.validation.constraints.NotBlank;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色-菜单功能关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class AccountAreaResetVO {
+
+	@NotBlank(message = "集团编码不可为空")
+	@ApiModelProperty(value = "集团编码,作为SQL条件", required = true, example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@NotBlank(message = "区域ID,不可为空")
+	@ApiModelProperty(value = "区域ID", example = "1001")
+	private String areaId; 		// 区域ID
+	
+}

+ 37 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/AccountProjectResetVO.java

@@ -0,0 +1,37 @@
+package com.persagy.person.pojo.vo.auth;
+
+import javax.validation.constraints.NotBlank;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色-菜单功能关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class AccountProjectResetVO {
+
+	@NotBlank(message = "集团编码不可为空")
+	@ApiModelProperty(value = "集团编码,作为SQL条件", required = true, example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	//@NotBlank(message = "项目ID,不可为空")
+	@ApiModelProperty(value = "项目ID", example = "1001")
+	private String projectId; 		// 项目ID
+	
+	@NotBlank(message = "区域ID,不可为空")
+	@ApiModelProperty(value = "区域ID", example = "1001")
+	private String areaId; 		// 区域ID
+	
+}

+ 34 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountProjectBatchVO.java

@@ -0,0 +1,34 @@
+package com.persagy.person.pojo.vo.auth;
+
+import java.util.List;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月26日:	上午11:24:05
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountProjectBatchVO extends BaseUserModel {
+	
+	@Valid
+	@NotEmpty(message = "权限集合,不可为空")
+	@ApiModelProperty(value = "权限集合", example = "Pj123456789")
+	private List<AccountProjectResetVO> auths; //权限集合
+	
+}

+ 34 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountProjectCreateVO.java

@@ -0,0 +1,34 @@
+package com.persagy.person.pojo.vo.auth;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月26日:	上午11:24:05
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountProjectCreateVO extends BaseGroupModel {
+	
+	@NotBlank(message = "区域ID,不可为空")
+	@ApiModelProperty(value = "区域ID", example = "1001")
+	private String areaId; 		// 区域ID
+	
+	//@NotBlank(message = "项目ID不可为空")
+	@ApiModelProperty(value = "项目ID,作为SQL条件", example = "Pj123456789")
+	private String projectId; // 项目ID
+	
+}

+ 35 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountProjectPageVO.java

@@ -0,0 +1,35 @@
+package com.persagy.person.pojo.vo.auth;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月26日:	上午11:24:05
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountProjectPageVO extends SaasAccountProjectQueryVO {
+	
+	@Min(value = 1, message = "分页页码,不可低于1")
+	@NotNull(message = "分页页码,不可为空")
+	@ApiModelProperty(value = "分页页码", example = "1", required = true)
+	private Integer page;
+
+	@Min(value = 1, message = "分页大小,不可低于1")
+	@NotNull(message = "分页大小,不可为空")
+	@ApiModelProperty(value = "分页大小", example = "10", required = true)
+	private Integer size;
+	
+}

+ 39 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountProjectQueryVO.java

@@ -0,0 +1,39 @@
+package com.persagy.person.pojo.vo.auth;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月26日:	上午11:24:05
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountProjectQueryVO extends BaseUserModel {
+	
+	@ApiModelProperty(value = "集团编码,作为SQL条件", example = "RC")
+	private String groupCode; 	// 集团编码
+	
+	@ApiModelProperty(value = "区域ID,作为SQL条件", example = "Pj123456789")
+	private String areaId; // 区域ID
+	
+	@ApiModelProperty(value = "项目ID,作为SQL条件", example = "Pj123456789")
+	private String projectId; // 项目ID
+	
+	@ApiModelProperty(value = "登录用户名", example = "zhangsan")
+	private String username; // 登录用户名
+	
+	@ApiModelProperty(value = "账号类型, 0-超级管理员(所有集团),1-单集团管理员(单集团),2-普通账号", example = "0")
+	private String accountType;		//账号类型, 0-超级管理员(所有集团),1-单集团管理员(单集团),2-普通账号
+	
+}

+ 40 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountRoleBatchVO.java

@@ -0,0 +1,40 @@
+package com.persagy.person.pojo.vo.auth;
+
+import java.util.List;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月16日:	下午4:08:00
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountRoleBatchVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "集团编码,作为SQL条件", example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@ApiModelProperty(value = "关联类型,0-主岗,1-副岗,2-业务超管默认角色", example = "0")
+	private String casType; 	// 关联类型,0-主岗,1-副岗,2-业务超管默认角色,这里的关联类型,会作为重置的条件,先进行删除
+	
+	@Valid
+	@NotEmpty(message = "角色集合,不可为空")
+	@ApiModelProperty(value = "角色", example = "123")
+	private List<SaasAccountRoleVO> roles; 	// 角色ID
+	
+}

+ 33 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountRoleCreateVO.java

@@ -0,0 +1,33 @@
+package com.persagy.person.pojo.vo.auth;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月16日:	下午4:08:00
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountRoleCreateVO extends BaseGroupModel {
+
+	@NotBlank(message = "角色ID,不可为空")
+	@ApiModelProperty(value = "角色ID", example = "123", required = true)
+	private String roleId; // 角色ID
+	
+	@ApiModelProperty(value = "关联类型,0-主岗,1-副岗,2-业务超管默认角色", example = "123", required = true)
+	private String casType;	//关联类型,0-主岗,1-副岗,2-业务超管默认角色
+	
+}

+ 49 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountRoleQueryVO.java

@@ -0,0 +1,49 @@
+package com.persagy.person.pojo.vo.auth;
+
+import java.util.Set;
+
+import javax.validation.constraints.NotBlank;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月16日:	下午4:08:00
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountRoleQueryVO{
+
+	@ApiModelProperty(value = "账号ID", required = true, example = "RY56122123152")
+	private String accountId; 	// 当前账号ID
+
+	@ApiModelProperty(value = "当前账号ID集合", example = "RY56122123152")
+	private Set<String> accountIds; 	// 当前账号ID集合
+	
+	@NotBlank(message = "账号归属,不可为空")
+	@ApiModelProperty(value = "账号归属", required = true, example = "0")
+	private String accountBelong; 	// 当前账号归属
+	
+	@NotBlank(message = "应用ID,不可为空")
+	@ApiModelProperty(value = "应用ID, PC-电脑端,APP-手机应用端", example = "PC", required = true)
+    private String appId;
+	
+	@ApiModelProperty(value = "集团编码,作为SQL条件", example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@ApiModelProperty(value = "角色ID", example = "123")
+	private String roleId; // 角色ID
+	
+	@ApiModelProperty(value = "关联类型,0-主岗,1-副岗,2-业务超管默认角色", example = "0")
+	private String casType; 	// 关联类型,0-主岗,1-副岗,2-业务超管默认角色,这里的关联类型,会作为重置的条件,先进行删除
+	
+}

+ 31 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasAccountRoleVO.java

@@ -0,0 +1,31 @@
+package com.persagy.person.pojo.vo.auth;
+
+import javax.validation.constraints.NotBlank;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月16日:	下午5:04:13
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasAccountRoleVO {
+
+	@NotBlank(message = "角色ID,不可为空")
+	@ApiModelProperty(value = "角色ID", example = "RO0134568781001")
+	private String roleId; 		// 角色ID
+
+	@ApiModelProperty(value = "关联类型,0-主岗,1-副岗,2-业务超管默认角色", example = "0")
+	private String casType; 	// 关联类型,0-主岗,1-副岗,2-业务超管默认角色,这里关联类型会直接插入数据库中,不做为重置的条件
+	
+}

+ 32 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasMenuFunctionVO.java

@@ -0,0 +1,32 @@
+package com.persagy.person.pojo.vo.auth;
+
+import javax.validation.constraints.NotBlank;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @version 
+ * @description 
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2021年3月16日:	下午5:04:13
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasMenuFunctionVO {
+
+	@NotBlank(message = "菜单ID,不可为空")
+	@ApiModelProperty(value = "菜单ID", example = "1001")
+	private String menuId; 		// 菜单ID
+
+	//@NotBlank(message = "功能ID,不可为空")
+	@ApiModelProperty(value = "功能ID", example = "1001")
+	private String functionId; 	// 功能ID
+	
+}

+ 40 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasRoleMenuBatchVO.java

@@ -0,0 +1,40 @@
+package com.persagy.person.pojo.vo.auth;
+
+import java.util.List;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色-菜单功能关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasRoleMenuBatchVO extends BaseGroupModel {
+
+	@NotBlank(message = "角色ID,不可为空")
+	@ApiModelProperty(value = "角色ID", example = "123")
+	private String roleId; 	// 角色ID
+
+	@Valid
+	@NotEmpty(message = "菜单功能权限集合,不可为空")
+	@ApiModelProperty(value = "菜单功能权限集合", example = "1001")
+	private List<SaasMenuFunctionVO> auths; 	// 菜单功能权限集合
+
+}

+ 39 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasRoleMenuCreateVO.java

@@ -0,0 +1,39 @@
+package com.persagy.person.pojo.vo.auth;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色-菜单功能关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasRoleMenuCreateVO extends BaseGroupModel {
+
+	@NotBlank(message = "角色ID,不可为空")
+	@ApiModelProperty(value = "角色ID", example = "123")
+	private String roleId; // 角色ID
+
+	@NotBlank(message = "菜单ID,不可为空")
+	@ApiModelProperty(value = "菜单ID", example = "1001")
+	private String menuId; // 菜单ID
+
+	//@NotBlank(message = "功能ID,不可为空")
+	@ApiModelProperty(value = "功能ID", example = "1001")
+	private String functionId; // 功能ID
+
+}

+ 34 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/auth/SaasRoleMenuQueryVO.java

@@ -0,0 +1,34 @@
+package com.persagy.person.pojo.vo.auth;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色-菜单功能关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasRoleMenuQueryVO extends BaseGroupModel {
+
+	@ApiModelProperty(value = "角色ID", example = "123")
+	private String roleId; // 角色ID
+
+	@ApiModelProperty(value = "菜单ID", example = "1001")
+	private String menuId; // 菜单ID
+
+	@ApiModelProperty(value = "功能ID", example = "1001")
+	private String functionId; // 功能ID
+
+}

+ 54 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/function/SaasFunctionCreateVO.java

@@ -0,0 +1,54 @@
+package com.persagy.person.pojo.vo.function;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 菜单信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@ApiModel
+public class SaasFunctionCreateVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "功能ID,更新时不可为空", example = "123")
+	private String id; // 功能ID
+	
+	@NotBlank(message = "菜单ID,不可为空")
+	@ApiModelProperty(value = "菜单ID", example = "123")
+	private String menuId; // 菜单ID
+
+	@NotBlank(message = "功能编码,不可为空")
+	@ApiModelProperty(value = "功能编码", example = "456")
+	private String funCode; // 功能编码
+
+	@NotBlank(message = "功能名称,不可为空")
+	@ApiModelProperty(value = "功能名称", example = "测试功能名称")
+	private String funName; // 功能名称
+	
+	@NotBlank(message = "功能URL,不可为空")
+	@ApiModelProperty(value = "功能URL", example = "http://127.0.0.1:8080/test.png")
+	private String funUrl;	// 功能URL
+
+	@NotNull(message = "功能顺序,不可为空")
+	@ApiModelProperty(value = "功能顺序", example = "1")
+	private Integer funSort; // 功能顺序
+
+	@ApiModelProperty(value = "备注", example = "测试功能点")
+	private String remark; // 备注
+
+}

+ 31 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/function/SaasFunctionDeleteVO.java

@@ -0,0 +1,31 @@
+package com.persagy.person.pojo.vo.function;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 菜单信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@ApiModel
+public class SaasFunctionDeleteVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "功能ID", example = "123456")
+	private String id; 		// 功能ID
+	
+	@ApiModelProperty(value = "菜单ID", example = "123456")
+	private String menuId; 	// 菜单ID
+	
+}

+ 43 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/function/SaasFunctionQueryVO.java

@@ -0,0 +1,43 @@
+package com.persagy.person.pojo.vo.function;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 菜单信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@ApiModel
+public class SaasFunctionQueryVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "集团编码,作为SQL条件", example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@ApiModelProperty(value = "角色ID", example = "123")
+	private String roleId; // 角色ID
+	
+	@ApiModelProperty(value = "菜单ID", example = "123")
+	private String menuId; // 菜单ID
+
+	@ApiModelProperty(value = "功能编码", example = "456")
+	private String funCode; // 功能编码
+
+	@ApiModelProperty(value = "功能名称", example = "测试功能名称")
+	private String funName; // 功能名称
+	
+	@ApiModelProperty(value = "最后一次操作者ID", example = "123")
+	private String updateUser; // 最后一次操作者ID
+
+}

+ 44 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/group/SaasGroupCreateVO.java

@@ -0,0 +1,44 @@
+package com.persagy.person.pojo.vo.group;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 集团信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasGroupCreateVO extends BaseGroupModel {
+
+	@NotBlank(message = "集团名称,不可为空")
+	@ApiModelProperty(value = "集团名称", example = "万达集团", required = true)
+	private String groupName; // 集团名称,业务保证唯一性
+
+	//@NotBlank(message = "集团部署,方式不可为空")
+	@ApiModelProperty(value = "集团部署方式,0-公有云,1-私有云", example = "0", required = true)
+	private String deployModel; // 集团部署方式,0-公有云,1-私有云
+
+	@ApiModelProperty(value = "集团图标", example = "http://127.0.0.1:9999/test.img")
+	private String groupIcon; // 集团图标
+
+	@ApiModelProperty(value = "集团描述", example = "测试集团")
+	private String groupDesc; // 集团描述
+	
+	@ApiModelProperty(value = "备注", example = "测试集团")
+	private String remark; // 备注
+
+}

+ 44 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/group/SaasGroupQueryVO.java

@@ -0,0 +1,44 @@
+package com.persagy.person.pojo.vo.group;
+
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 集团信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasGroupQueryVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "集团编码", example = "WD")
+	private String groupCode; // 集团编码
+
+	@ApiModelProperty(value = "集团名称,支持模糊查询", example = "万达集团")
+	private String groupName; // 集团名称,业务保证唯一性
+
+	@ApiModelProperty(value = "集团部署方式,0-公有云,1-私有云", example = "0")
+	private String deployModel; // 集团部署方式,0-公有云,1-私有云
+
+	@ApiModelProperty(value = "数据同步状态,0-数据同步失败,1-数据同步成功,2-未同步", example = "0")
+	private String syncState; 	// 数据同步状态,0-数据同步失败,1-数据同步成功,2-未同步
+
+	@ApiModelProperty(value = "最后一次操作者ID", example = "zhangsan")
+	private String updateUser; // 最后一次操作者ID
+
+	@ApiModelProperty(value = "0-不可用,1-可用,默认1", example = "1")
+	private Integer valid = SaasCommonConstant.STATUS_1; // 0-不可用,1-可用
+
+}

+ 65 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/menu/SaasMenuCreateVO.java

@@ -0,0 +1,65 @@
+package com.persagy.person.pojo.vo.menu;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 菜单信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@ApiModel
+public class SaasMenuCreateVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "菜单ID,更新时不可为空", example = "123456")
+	private String id; // 菜单ID
+	
+	@ApiModelProperty(value = "上级菜单ID", example = "123456")
+	private String parentId; // 上级菜单ID
+
+	@NotBlank(message = "菜单编码,不可为空")
+	@ApiModelProperty(value = "菜单编码", example = "ceshi", required = true)
+	private String menuCode; // 菜单编码
+	
+	@NotBlank(message = "菜单名称,不可为空")
+	@ApiModelProperty(value = "菜单名称", example = "测试菜单", required = true)
+	private String menuName; // 菜单名称
+
+	@ApiModelProperty(value = "菜单URL", example = "/account/query")
+	private String menuUrl;  // 菜单URL
+
+	@ApiModelProperty(value = "URL类型,0-相对路径,1-绝对路径", example = "0")
+	private String urlType;	//URL类型,0-相对路径,1-绝对路径
+	
+	//@NotBlank(message = "菜单图标,不可为空")
+	@ApiModelProperty(value = "菜单图标", example = "http://127.0.0.1:8080/test.img")
+	private String menuIcon; // 菜单图标
+	
+	@Min(value = 1, message = "菜单顺序,不可小于1")
+	@NotNull(message = "菜单顺序,不可为空")
+	@ApiModelProperty(value = "菜单顺序", example = "1", required = true)
+	private Integer menuSort; // 菜单顺序
+
+	@NotBlank(message = "菜单类型,不可为空")
+	@ApiModelProperty(value = "菜单类型,0-系统菜单,1-标准业务菜单,2-IBMS菜单,3-APP菜单", example = "0")
+	private String menuType;	//菜单类型,0-系统菜单,1-标准业务菜单,2-IBMS菜单,3-APP菜单
+	
+	@ApiModelProperty(value = "备注", example = "测试菜单")
+	private String remark;   // 备注
+
+}

+ 31 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/menu/SaasMenuDeleteVO.java

@@ -0,0 +1,31 @@
+package com.persagy.person.pojo.vo.menu;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 菜单信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ToString
+@ApiModel
+public class SaasMenuDeleteVO extends BaseGroupModel {
+
+	@NotBlank(message = "菜单ID,不可为空")
+	@ApiModelProperty(value = "菜单ID", example = "123456")
+	private String id; // 菜单ID
+	
+}

+ 37 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/menu/SaasMenuQueryVO.java

@@ -0,0 +1,37 @@
+package com.persagy.person.pojo.vo.menu;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 菜单信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasMenuQueryVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "集团编码,作为SQL条件",example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@ApiModelProperty(value = "菜单ID", example = "ME123456789")
+	private String menuId; 		// 菜单ID
+	
+	@ApiModelProperty(value = "菜单类型,0-系统菜单,1-标准业务菜单,2-IBMS菜单,3-APP菜单", example = "0")
+	private String menuType; 		// 菜单类型,0-系统菜单,1-标准业务菜单,2-IBMS菜单,3-APP菜单
+	
+	@ApiModelProperty(value = "是否仅查询出菜单树,true-是,默认false", example = "false")
+	private boolean isMenu = false; 	// 是否仅查询出菜单树,true-是,默认false
+	
+}

+ 38 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/project/SaasProjectAreaUpdateVO.java

@@ -0,0 +1,38 @@
+package com.persagy.person.pojo.vo.project;
+
+import java.util.List;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasProjectAreaUpdateVO extends BaseGroupModel {
+
+	@NotBlank(message = "区域ID,不可为空")
+	@ApiModelProperty(value = "项目所属区域", example = "123456", required = true)
+	private String areaId; 		// 项目所属区域,必须为最底层的区域
+	
+	@NotEmpty(message = "项目ID集合,不可为空")
+	@ApiModelProperty(value = "项目ID集合", example = "[Pj123456789]", required = true)
+	private List<String> projectIds; 	// 项目ID
+
+}

+ 71 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/project/SaasProjectCreateVO.java

@@ -0,0 +1,71 @@
+package com.persagy.person.pojo.vo.project;
+
+import java.util.Date;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseGroupModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasProjectCreateVO extends BaseGroupModel {
+
+	@ApiModelProperty(value = "主键ID,更新时,不可为空", example = "123456adzxzc")
+	private String id; 	// 主键ID
+	
+	@NotBlank(message = "项目ID,不可为空")
+	@ApiModelProperty(value = "项目ID", example = "Pj123456789", required = true)
+	private String projectId; 	// 项目ID,与集团编码联合唯一,业务保证
+
+	//@NotBlank(message = "区域ID,不可为空")
+	@ApiModelProperty(value = "项目所属区域", example = "123456")
+	private String areaId; 		// 项目所属区域,必须为最底层的区域
+
+	@NotBlank(message = "项目本地编码,不可为空")
+	@ApiModelProperty(value = "项目本地编码", example = "123456789", required = true)
+	private String projectLocalId; // 项目本地编码
+
+	@NotBlank(message = "项目名称,不可为空")
+	@ApiModelProperty(value = "项目名称,支持模糊查询", example = "测试项目", required = true)
+	private String projectName; // 项目名称
+	
+	//@NotBlank(message = "项目所在省,不可为空")
+	@ApiModelProperty(value = "项目所在省", example = "123456789")
+	private String provinceCode; //项目所在省
+
+	//@NotBlank(message = "项目所在市,不可为空")
+	@ApiModelProperty(value = "项目所在市", example = "123456789")
+	private String cityCode;	//项目所在市
+	
+	//@NotBlank(message = "项目所在区,不可为空")
+	@ApiModelProperty(value = "项目所在区", example = "123456789")
+	private String zoneCode;	//项目所在区
+	
+	//@NotBlank(message = "项目详细地址,不可为空")
+	@ApiModelProperty(value = "项目详细地址", example = "123456789")
+	private String location;	//项目详细地址
+	
+	//@NotBlank(message = "项目开业时间,不可为空")
+	@ApiModelProperty(value = "项目开业时间", example = "123456789")
+	private Date openTime;	//项目开业时间
+
+	@ApiModelProperty(value = "备注信息", example = "测试项目")
+	private String remark; // 备注
+	
+}

+ 113 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/project/SaasProjectExcel.java

@@ -0,0 +1,113 @@
+package com.persagy.person.pojo.vo.project;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.usermodel.Font;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.HeadFontStyle;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @version 
+ * @description 传感器数据上传excel解析类
+ * @company persagy
+ * @author zhangqiankun
+ * @since 2020年11月26日:	下午12:30:39
+ */
+@Getter
+@Setter
+@HeadFontStyle(color = Font.COLOR_NORMAL)
+@ApiModel(description = "项目数据上传excel解析类")
+public class SaasProjectExcel {
+	
+	public static final String SHEET_NAME_0 = "项目数据模板";
+	
+	@ExcelProperty(value = "序号", index=0)
+	private String index; 	// 序号
+	
+	@ColumnWidth(30)
+	@HeadFontStyle(color = Font.COLOR_RED)
+	@ExcelProperty(value = "集团编码", index=1)
+	private String groupCode; // 集团编码
+
+	@ColumnWidth(30)
+	//@HeadFontStyle(color = Font.COLOR_RED)
+	@ExcelProperty(value = "项目所属区域", index=2)
+	private String areaId; 	// 项目所属区域
+
+	@ColumnWidth(20)
+	@HeadFontStyle(color = Font.COLOR_RED)
+	@ExcelProperty(value = "项目ID", index=3)
+	private String projectId; // 项目ID
+	
+	@ColumnWidth(20)
+	@HeadFontStyle(color = Font.COLOR_RED)
+	@ExcelProperty(value = "项目本地编码", index=4)
+	private String projectLocalId; // 项目本地编码
+
+	@ColumnWidth(40)
+	@HeadFontStyle(color = Font.COLOR_RED)
+	@ExcelProperty(value = "项目名称", index=5)
+	private String projectName;		// 项目名称
+	
+	@ColumnWidth(20)
+	//@HeadFontStyle(color = Font.COLOR_RED)
+	@ExcelProperty(value = "项目所在省", index=6)
+	private String provinceCode; // 项目所在省
+	
+	@ColumnWidth(20)
+	//@HeadFontStyle(color = Font.COLOR_RED)
+	@ExcelProperty(value = "项目所在市", index=7)
+	private String cityCode; 	// 项目所在市
+	
+	@ColumnWidth(20)
+	//@HeadFontStyle(color = Font.COLOR_RED)
+	@ExcelProperty(value = "项目所在区", index=8)
+	private String zoneCode; 	// 项目所在区
+	
+	@ColumnWidth(20)
+	//@HeadFontStyle(color = Font.COLOR_RED)
+	@ExcelProperty(value = "项目详细地址", index=9)
+	private String location; 	// 项目详细地址
+
+	@ColumnWidth(40)
+	@ExcelProperty(value = "备注", index=10)
+	private String remark;
+	
+	/**
+	 * 获取模板样例数据
+	 * @return
+	 */
+	public static List<SaasProjectExcel> getDemoData() {
+		List<SaasProjectExcel> model = new ArrayList<SaasProjectExcel>(2);
+		SaasProjectExcel one = new SaasProjectExcel();
+		one.setIndex("1");
+		one.setProjectId("Pj1209010205");
+		one.setProjectLocalId("1209010205");
+		one.setProjectName("测试项目一");
+		one.setProvinceCode("省份编码");
+		one.setCityCode("城市编码");
+		one.setZoneCode("区域编码");
+		one.setRemark("测试项目一");
+		
+		SaasProjectExcel two = new SaasProjectExcel();
+		two.setIndex("2");
+		two.setProjectId("Pj1209010206");
+		two.setProjectLocalId("1209010205");
+		two.setProjectName("测试项目二");
+		two.setProvinceCode("省份编码");
+		two.setCityCode("城市编码");
+		two.setZoneCode("区域编码");
+		two.setRemark("测试项目二");
+		
+		model.add(one);
+		model.add(two);
+		return model;
+	}
+}

+ 36 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/project/SaasProjectPageVO.java

@@ -0,0 +1,36 @@
+package com.persagy.person.pojo.vo.project;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasProjectPageVO extends SaasProjectQueryVO {
+
+	@Min(value = 1, message = "分页页码,不可低于1")
+	@NotNull(message = "分页页码,不可为空")
+	@ApiModelProperty(value = "分页页码", example = "1", required = true)
+	private Integer page;
+
+	@Min(value = 1, message = "分页大小,不可低于1")
+	@NotNull(message = "分页大小,不可为空")
+	@ApiModelProperty(value = "分页大小", example = "10", required = true)
+	private Integer size;
+
+}

+ 70 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/project/SaasProjectQueryVO.java

@@ -0,0 +1,70 @@
+package com.persagy.person.pojo.vo.project;
+
+import java.util.Date;
+import java.util.Set;
+
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasProjectQueryVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "集团编码,作为SQL条件", required = true, example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@ApiModelProperty(value = "主键ID", example = "123456adzxzc")
+	private String id; 	// 主键ID
+	
+	@ApiModelProperty(value = "项目ID", example = "Pj123456789")
+	private String projectId; 	// 项目ID
+
+	@ApiModelProperty(value = "项目ID集合,最大999", example = "Pj123456789")
+	private Set<String> projectIds; 	// 项目ID集合
+	
+	@ApiModelProperty(value = "项目所属区域", example = "123456")
+	private String areaId; 		// 项目所属区域,必须为最底层的区域
+
+	@ApiModelProperty(value = "项目本地编码", example = "123456789")
+	private String projectLocalId; // 项目本地编码
+
+	@ApiModelProperty(value = "项目名称,支持模糊查询", example = "测试项目")
+	private String projectName; // 项目名称
+
+	@ApiModelProperty(value = "项目所在省", example = "123456789")
+	private String provinceCode; //项目名所在省
+
+	@ApiModelProperty(value = "项目所在市", example = "123456789")
+	private String cityCode;	//项目名所在市
+	
+	@ApiModelProperty(value = "项目所在区", example = "123456789")
+	private String zoneCode;	//项目名所在区
+	
+	@ApiModelProperty(value = "项目开业时间", example = "123456789")
+	private Date openTime;	//项目开业时间
+	
+	@ApiModelProperty(value = "最后一次操作者ID", example = "zhangsan")
+	private String updateUser; // 最后一次操作者ID
+
+	@ApiModelProperty(value = "是否展示空的区域信息,即不存在项目的空区域", example = "zhangsan")
+	private Boolean showEmptyArea = true; 	// 是否展示空的区域信息,即不存在项目的空区域
+	
+	private Integer valid = SaasCommonConstant.STATUS_1; // 0-不可用,1-可用
+
+}

+ 53 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/role/SaasRoleCreateVO.java

@@ -0,0 +1,53 @@
+package com.persagy.person.pojo.vo.role;
+
+import java.util.List;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseUserModel;
+import com.persagy.person.pojo.vo.auth.SaasMenuFunctionVO;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasRoleCreateVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "集团编码,作为SQL条件", required = true, example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@ApiModelProperty(value = "角色ID,更新时不可为空", example = "1001")
+	private String id; 			// 角色ID
+	
+	@ApiModelProperty(value = "角色编码", example = "zhangsan")
+	private String roleCode; 	// 角色编码
+	
+	@NotBlank(message = "角色名称,不可为空")
+	@ApiModelProperty(value = "角色名称", example = "zhangsan")
+	private String roleName; 	// 角色名称
+	
+	@NotBlank(message = "角色类型不可为空")
+	@ApiModelProperty(value = "角色类型,0-系统角色,1-业务角色, 2-业务超管默认角色", example = "zhangsan")
+	private String roleType; // 角色类型,0-系统角色,1-业务角色, 2-业务超管默认角色
+
+	@ApiModelProperty(value = "菜单功能权限集合", example = "[{menuId:123, functionId:456}]")
+	private List<SaasMenuFunctionVO> auths; 	// 菜单功能权限集合
+	
+	@ApiModelProperty(value = "备注信息", example = "测试角色")
+	private String remark; 		// 备注
+	
+}

+ 34 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/role/SaasRoleDeleteVO.java

@@ -0,0 +1,34 @@
+package com.persagy.person.pojo.vo.role;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasRoleDeleteVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "集团编码,作为SQL条件", example = "RC")
+	private String groupCode; 	// 所属集团编码
+	
+	@NotBlank(message = "角色ID,不可为空")
+	@ApiModelProperty(value = "角色ID", example = "1001")
+	private String id; // 角色ID
+	
+}

+ 36 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/role/SaasRolePageVO.java

@@ -0,0 +1,36 @@
+package com.persagy.person.pojo.vo.role;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasRolePageVO extends SaasRoleQueryVO {
+
+	@Min(value = 1, message = "分页页码,不可低于1")
+	@NotNull(message = "分页页码,不可为空")
+	@ApiModelProperty(value = "分页页码", example = "1", required = true)
+	private Integer page;
+
+	@Min(value = 1, message = "分页大小,不可低于1")
+	@NotNull(message = "分页大小,不可为空")
+	@ApiModelProperty(value = "分页大小", example = "10", required = true)
+	private Integer size;
+
+}

+ 37 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/role/SaasRoleQueryByNameVO.java

@@ -0,0 +1,37 @@
+package com.persagy.person.pojo.vo.role;
+
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseUserModel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import javax.validation.constraints.NotBlank;
+import java.util.Set;
+
+/**
+ * 角色信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasRoleQueryByNameVO  {
+
+
+    @NotBlank(message = "集团编码,不可为空")
+	@ApiModelProperty(value = "集团编码,作为SQL条件", required = true, example = "RC")
+	private String groupCode; 	// 所属集团编码
+
+    @NotBlank(message = "角色名称,不可为空")
+	@ApiModelProperty(value = "角色名称,支持模糊查询", example = "zhangsan")
+	private String roleName; 	// 角色名称
+
+}

+ 57 - 0
saas-account/src/main/java/com/persagy/person/pojo/vo/role/SaasRoleQueryVO.java

@@ -0,0 +1,57 @@
+package com.persagy.person.pojo.vo.role;
+
+import java.util.Set;
+
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 角色信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasRoleQueryVO extends BaseUserModel {
+	
+	@ApiModelProperty(value = "集团编码,作为SQL条件", required = true, example = "RC")
+	private String groupCode; 	// 所属集团编码
+
+	@ApiModelProperty(value = "角色ID", example = "1001")
+	private String id; 			// 角色ID
+
+	@ApiModelProperty(value = "角色ID集合", example = "1001")
+	private Set<String> roleIds; // 角色ID集合
+	
+	@ApiModelProperty(value = "角色编码", example = "1001")
+	private String roleCode; 	// 角色编码
+
+	@ApiModelProperty(value = "角色名称,支持模糊查询", example = "zhangsan")
+	private String roleName; 	// 角色名称
+
+	@ApiModelProperty(value = "角色类型,0-系统角色,1-业务角色, 2-业务超管默认角色", example = "zhangsan")
+	private String roleType; 	// 角色类型,0-系统角色,1-业务角色, 2-业务超管默认角色
+	
+	@ApiModelProperty(value = "最后一次操作者ID", example = "zhangsan")
+	private String updateUser; 	// 最后一次操作者ID
+
+	@ApiModelProperty(value = "是否统计菜单数量,true-统计,默认false", example = "false")
+	private boolean countMenu = false; // 是否统计菜单数量,true-统计,默认false
+	
+	@ApiModelProperty(value = "是否统计功能点数量,true-统计,默认false", example = "false")
+	private boolean countFunction = false; // 是否统计功能点数量,true-统计,默认false
+
+	private Integer valid = SaasCommonConstant.STATUS_1; // 0-不可用,1-可用
+
+}

+ 54 - 0
saas-account/src/main/java/com/persagy/person/service/ISaasAccountProjectService.java

@@ -0,0 +1,54 @@
+package com.persagy.person.service;
+
+import java.util.List;
+import java.util.Set;
+
+import com.persagy.common.service.ISuperService;
+import com.persagy.person.pojo.dto.SaasAccountProject;
+import com.persagy.person.pojo.vo.auth.AccountProjectResetVO;
+
+/**
+ * 账号-集团项目关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+public interface ISaasAccountProjectService extends ISuperService<SaasAccountProject> {
+
+	/**
+	 * 删除新增账号-集团项目关联信息
+	 * @param accountId 
+	 * @param auths
+	 * @return
+	 */
+	boolean resetSaasAccountProject(String accountId, List<AccountProjectResetVO> auths);
+
+	/**
+	 * 添加一条默认的账号、集团、未分区区域的关联关系
+	 * 
+	 * @param accountId
+	 * @param groupCode
+	 * @return
+	 */
+	boolean addDefaultAccountArea(String accountId, String groupCode);
+
+	/**
+	 * 获取已被分配的集团区域ID集合
+	 * @param accountId
+	 * @param groupCode
+	 * @return
+	 */
+	Set<String> queryAccountAreaIds(String accountId, String groupCode);
+
+	/**
+	 * 更新或新增账号-集团区域项目关联关系
+	 * 
+	 * @param data
+	 * @return
+	 */
+	boolean replaceAccountProject(List<SaasAccountProject> data);
+
+}
+

+ 49 - 0
saas-account/src/main/java/com/persagy/person/service/ISaasAccountRoleService.java

@@ -0,0 +1,49 @@
+package com.persagy.person.service;
+
+import java.util.List;
+
+import com.persagy.common.service.ISuperService;
+import com.persagy.person.pojo.dto.SaasAccountRole;
+import com.persagy.person.pojo.vo.auth.SaasAccountRoleVO;
+
+/**
+ * 账号-角色关联信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+public interface ISaasAccountRoleService extends ISuperService<SaasAccountRole> {
+
+	/**
+	 * 验证此角色是否允许被删除
+	 * 
+	 * @param groupCode
+	 * @param roleId
+	 * @return true-允许
+	 */
+	boolean isAllowDeleteRole(String groupCode, String roleId);
+
+	/**
+	 * 先删除,在新增,批量插入账号角色关联关系
+	 * 
+	 * @param groupCode
+	 * @param accountId
+	 * @param casType
+	 * @param roles
+	 * @return
+	 */
+	boolean resetSaasAccountRole(String groupCode, String accountId, String casType, List<SaasAccountRoleVO> roles);
+
+	/**
+	 * 添加默认的业务超管账号与业务超管默认角色的关联关系
+	 * 
+	 * @param accountId
+	 * @param groupCode
+	 * @return
+	 */
+	boolean addDeafultAccountRole(String accountId, String groupCode);
+
+}
+

+ 67 - 0
saas-account/src/main/java/com/persagy/person/service/ISaasAccountService.java

@@ -0,0 +1,67 @@
+package com.persagy.person.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.persagy.common.service.ISuperService;
+import com.persagy.person.pojo.dto.SaasAccount;
+
+/**
+ * 账号信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+public interface ISaasAccountService extends ISuperService<SaasAccount> {
+
+	/**
+	 * 获取账号信息 
+	 * 
+	 * @param id
+	 * @param groupCode
+	 * @param username
+	 * @return
+	 */
+	SaasAccount getOne(String id, String groupCode, String username);
+	
+	/**
+	 * 获取账号列表,此方法会关联出集团名称信息
+	 * 
+	 * @param saasAccount
+	 * @param startRow
+	 * @param size
+	 * @return
+	 */
+	Page<SaasAccount> queryAccountPageList(SaasAccount saasAccount, int page, int size);
+	
+	/**
+	 * 获取账号的查询条件
+	 * 
+	 * @param saasAccount
+	 * @return
+	 */
+	LambdaQueryWrapper<SaasAccount> getQueryWrapper(SaasAccount saasAccount);
+	
+	/**
+	 * 验证账号名称的唯一性
+	 * 
+	 * @param groupCode 这里先废弃,默认账号用户名全局唯一
+	 * @param username
+	 * @param mail
+	 * @param phone
+	 * @param id
+	 * @param isUpdate,是否是更新时调用,true-时,id-必须存在
+	 * @return
+	 */
+	boolean validAccountName(String username, String mail, String phone, String id, boolean isUpdate);
+
+
+    /**
+     * 获取账号的查询条件
+     * @param saasAccount
+     * @return
+     */
+    LambdaQueryWrapper<SaasAccount> getQueryWrapperByUsername(SaasAccount saasAccount);
+}
+

+ 58 - 0
saas-account/src/main/java/com/persagy/person/service/ISaasAreaService.java

@@ -0,0 +1,58 @@
+package com.persagy.person.service;
+
+import java.util.List;
+
+import com.persagy.common.service.ISuperService;
+import com.persagy.person.pojo.dto.SaasArea;
+
+/**
+ * 区域信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+public interface ISaasAreaService extends ISuperService<SaasArea> {
+
+	/**
+     * 获取一条区域信息
+     * 
+     * @param id
+     * @param groupCode
+     * @param areaCode
+     * @param areaName
+     * @return
+     */
+	public SaasArea getAreaOne(String id, String groupCode, String areaCode, String areaName);
+	
+	/**
+	 * 获取被允许访问的区域信息
+	 * 
+	 * @param queryVO
+	 * @return
+	 */
+	List<SaasArea> queryAllowSaasAreaList(String accountId, SaasArea saasArea);
+	
+	/**
+	 * 验证区域编码和区域名称,在该集团下是否唯一
+	 * 
+	 * @param groupCode
+	 * @param areaCode
+	 * @param areaName
+	 * @param id 更新时,id不可为空
+	 * @return
+	 */
+	boolean validAreaCodeAndName(String groupCode, String areaCode, String areaName, String id);
+
+	/**
+	 * 创建一条空区域记录
+	 * 
+	 * @param groupCode
+	 * @param updateUser
+	 * @return 返回区域ID,返回空时,代表新增失败
+	 */
+	String createEmptyAreaInfo(String groupCode, String updateUser);
+
+}
+

+ 37 - 0
saas-account/src/main/java/com/persagy/person/service/ISaasFunctionService.java

@@ -0,0 +1,37 @@
+package com.persagy.person.service;
+
+import java.util.List;
+
+import com.persagy.common.service.ISuperService;
+import com.persagy.person.pojo.dto.SaasFunction;
+
+/**
+ * 功能信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+public interface ISaasFunctionService extends ISuperService<SaasFunction> {
+
+	/**
+	 * 查询出该账号下某菜单的功能点信息集合,关联查询
+	 * @param accountId
+	 * @param groupCode
+	 * @param menuId
+	 * @return
+	 */
+	List<SaasFunction> queryAccountFunctionList(String accountId, String groupCode, String menuId);
+	
+	/**
+	 * 查询出该角色下某菜单的功能点信息集合,关联查询
+	 * @param groupCode
+	 * @param roleId
+	 * @param menuId
+	 * @return
+	 */
+	List<SaasFunction> queryRoleFunctionList(String groupCode, String roleId, String menuId);
+
+}
+

+ 52 - 0
saas-account/src/main/java/com/persagy/person/service/ISaasGroupService.java

@@ -0,0 +1,52 @@
+package com.persagy.person.service;
+
+import java.util.List;
+
+import com.persagy.common.service.ISuperService;
+import com.persagy.person.pojo.dto.SaasGroup;
+
+/**
+ * 集团信息
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+public interface ISaasGroupService extends ISuperService<SaasGroup> {
+
+	/**
+	 * 获取集团信息
+	 * @param groupCode
+	 * @return
+	 */
+	SaasGroup getOne(String groupCode);
+	
+	/**
+	 * 分别验证集团编码与集团名称的唯一性
+	 * 
+	 * @param groupCode
+	 * @param groupName
+	 * @param isUpdate 是否是更新时调用的,true-是
+	 * @return true-唯一,及数据库不存在(更新时,将会验证groupName是否属于此groupCode,属于-true);false-不唯一
+	 */
+	boolean validGroupCodeOrName(String groupCode, String groupName, boolean isUpdate);
+	
+	/**
+	 * 查询集团信息列表,表关联查询(权限控制)
+	 * @param saasGroup
+	 * @param accountId 
+	 * @return
+	 */
+	List<SaasGroup> queryAllowGroupInfo(SaasGroup saasGroup, String accountId);
+
+	/**
+	 * 查询没有项目信息的被选中的集团信息
+	 * @param groupCode
+	 * @param accountId
+	 * @return
+	 */
+	List<SaasGroup> queryGroupAndEmptyProject(String groupCode, String accountId);
+	
+}
+

+ 0 - 0
saas-account/src/main/java/com/persagy/person/service/ISaasMenuService.java


部分文件因文件數量過多而無法顯示