diff options
Diffstat (limited to 'UI source code')
537 files changed, 47199 insertions, 0 deletions
diff --git a/UI source code/dns-dev-2.0/.gitignore b/UI source code/dns-dev-2.0/.gitignore new file mode 100644 index 0000000..9acb04a --- /dev/null +++ b/UI source code/dns-dev-2.0/.gitignore @@ -0,0 +1,7 @@ +### IDEA ### +.idea/* +*.iml +*/target/* +*/*.iml +/.gradle/ +/application.pid
\ No newline at end of file diff --git a/UI source code/dns-dev-2.0/LICENSE b/UI source code/dns-dev-2.0/LICENSE new file mode 100644 index 0000000..ca38718 --- /dev/null +++ b/UI source code/dns-dev-2.0/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "{}" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright 2019-2020 Zheng Jie + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
\ No newline at end of file diff --git a/UI source code/dns-dev-2.0/README.md b/UI source code/dns-dev-2.0/README.md new file mode 100644 index 0000000..6284064 --- /dev/null +++ b/UI source code/dns-dev-2.0/README.md @@ -0,0 +1,72 @@ +<h1 style="text-align: center">DiamondV + +</div> + +#### 项目简介 + +一个基于 Spring Boot 2.1.0 、 Spring Boot Jpa、mybatis-plus、 JWT、Spring Security、Redis、Vue的前后端分离的后台管理系统 + +**账号密码:** `admin / 123456` + +**打包:** `mvn clean install` + +#### 项目源码 + +| | 后端源码 | 前端源码 | +| ---- | ------------------------------ | ----------------------------------------- | +| 地址 | http://192.168.40.125/kjch/dns | http://192.168.40.125/kjch/dns_mapping_ui | + +#### 主要特性 + +- 使用最新技术栈,社区资源丰富。 +- 高效率开发,代码生成器可一键生成前后端代码 +- 支持数据字典,可方便地对一些状态进行管理 +- 支持接口限流,避免恶意请求导致服务层压力过大 +- 支持接口级别的功能权限与数据权限,可自定义操作 +- 自定义权限注解与匿名接口注解,可快速对接口拦截与放行 +- 对一些常用地前端组件封装:表格数据请求、数据字典等 +- 前后端统一异常拦截处理,统一输出异常,避免繁琐的判断 +- 支持在线用户管理与服务器性能监控,支持限制单用户登录 +- 支持运维管理,可方便地对远程服务器的应用进行部署与管理 + +#### 系统功能 + +- 用户管理:提供用户的相关配置,新增用户后,默认密码为123456 +- 角色管理:对权限与菜单进行分配,可根据部门设置角色的数据权限 +- 菜单管理:已实现菜单动态路由,后端可配置化,支持多级菜单 +- 部门管理:可配置系统组织架构,树形表格展示 +- 岗位管理:配置各个部门的职位 +- 字典管理:可维护常用一些固定的数据,如:状态,性别等 +- 系统日志:记录用户操作日志与异常日志,方便开发人员定位排错 +- SQL监控:采用druid 监控数据库访问性能,默认用户名admin,密码123456 +- 定时任务:整合Quartz做定时任务,加入任务日志,任务运行情况一目了然 +- 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务 +- 邮件工具:配合富文本,发送html格式的邮件 +- 七牛云存储:可同步七牛云存储的数据到系统,无需登录七牛云直接操作云数据 +- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试 +- 服务监控:监控服务器的负载情况 +- 运维管理:一键部署你的应用 + +#### 项目结构 + +项目采用按功能分模块的开发方式,结构如下 + +- `dns-common` 为系统的公共模块,各种工具类,公共配置存在该模块 +- `dns-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块 +- `dns-logging` 为系统的日志模块,其他模块如果需要记录日志需要引入该模块 +- 详细结构 + +``` +- dns-common 公共模块 + - annotation 为系统自定义注解 + - aspect 自定义注解的切面 + - base 提供了Entity、DTO基类和mapstruct的通用mapper + - config 自定义权限实现、redis配置、swagger配置、Rsa配置等 + - exception 项目统一异常的处理 + - utils 系统通用工具类 +- dns-system 系统核心模块(系统启动入口) + - config 配置跨域与静态资源,与数据权限 + - thread 线程池相关 + - modules 系统相关模块(登录授权、系统监控、定时任务、运维管理,测绘等) +- dns-logging 系统日志模块 +``` diff --git a/UI source code/dns-dev-2.0/dns-common/pom.xml b/UI source code/dns-dev-2.0/dns-common/pom.xml new file mode 100644 index 0000000..33734bb --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/pom.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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"> + <parent> + <artifactId>dns</artifactId> + <groupId>com.example</groupId> + <version>2.6</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <properties> + <hutool.version>5.3.4</hutool.version> + </properties> + + <artifactId>dns-common</artifactId> + <name>dns-common</name> + + <dependencies> + <!--工具包--> + <dependency> + <groupId>cn.hutool</groupId> + <artifactId>hutool-all</artifactId> + <version>${hutool.version}</version> + </dependency> + </dependencies> +</project> diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/AnonymousAccess.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/AnonymousAccess.java new file mode 100644 index 0000000..9cffb51 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/AnonymousAccess.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.annotation; + +import java.lang.annotation.*; + +/** + * @author jacky + * 用于标记匿名访问方法 + */ +@Inherited +@Documented +@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface AnonymousAccess { + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/DataPermission.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/DataPermission.java new file mode 100644 index 0000000..7fa3e3f --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/DataPermission.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * <p> + * 用于判断是否过滤数据权限 + * 1、如果没有用到 @OneToOne 这种关联关系,只需要填写 fieldName [参考:DeptQueryCriteria.class] + * 2、如果用到了 @OneToOne ,fieldName 和 joinName 都需要填写,拿UserQueryCriteria.class举例: + * 应该是 @DataPermission(joinName = "dept", fieldName = "id") + * </p> + * + * @website https://el-admin.vip + * 2020-05-07 + **/ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface DataPermission { + + /** + * Entity 中的字段名称 + */ + String fieldName() default ""; + + /** + * Entity 中与部门关联的字段名称 + */ + String joinName() default ""; +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Limit.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Limit.java new file mode 100644 index 0000000..ee285de --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Limit.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.annotation; + +import com.example.aspect.LimitType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author jacky + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Limit { + + // 资源名称,用于描述接口功能 + String name() default ""; + + // 资源 key + String key() default ""; + + // key prefix + String prefix() default ""; + + // 时间的,单位秒 + int period(); + + // 限制访问次数 + int count(); + + // 限制类型 + LimitType limitType() default LimitType.CUSTOMER; + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Query.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Query.java new file mode 100644 index 0000000..e21d60b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/Query.java @@ -0,0 +1,87 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Query { + + // Dong ZhaoYang 2017/8/7 基本对象的属性名 + String propName() default ""; + // Dong ZhaoYang 2017/8/7 查询方式 + Type type() default Type.EQUAL; + + /** + * 连接查询的属性名,如User类中的dept + */ + String joinName() default ""; + + /** + * 默认左连接 + */ + Join join() default Join.LEFT; + + /** + * 多字段模糊搜索,仅支持String类型字段,多个用逗号隔开, 如@Query(blurry = "email,username") + */ + String blurry() default ""; + + enum Type { + // jie 2019/6/4 相等 + EQUAL + // Dong ZhaoYang 2017/8/7 大于等于 + , GREATER_THAN + // Dong ZhaoYang 2017/8/7 小于等于 + , LESS_THAN + // Dong ZhaoYang 2017/8/7 中模糊查询 + , INNER_LIKE + // Dong ZhaoYang 2017/8/7 左模糊查询 + , LEFT_LIKE + // Dong ZhaoYang 2017/8/7 右模糊查询 + , RIGHT_LIKE + // Dong ZhaoYang 2017/8/7 小于 + , LESS_THAN_NQ + // jie 2019/6/4 包含 + , IN + // 不包含 + , NOT_IN + // 不等于 + ,NOT_EQUAL + // between + ,BETWEEN + // 不为空 + ,NOT_NULL + // 为空 + ,IS_NULL + } + + /** + * + * 适用于简单连接查询,复杂的请自定义该注解,或者使用sql查询 + */ + enum Join { + /** jie 2019-6-4 13:18:30 */ + LEFT, RIGHT, INNER + } + +} + diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousDeleteMapping.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousDeleteMapping.java new file mode 100644 index 0000000..10fbef4 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousDeleteMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.example.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code DELETE} requests onto specific handler + * methods. + * 支持匿名访问 DeleteMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousPatchMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.DELETE) +public @interface AnonymousDeleteMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousGetMapping.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousGetMapping.java new file mode 100644 index 0000000..85d6a78 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousGetMapping.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.example.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code GET} requests onto specific handler + * methods. + * <p> + * 支持匿名访问 GetMapping + * + * @author liaojinlong + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.GET) +public @interface AnonymousGetMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + * + * @since 4.3.5 + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPatchMapping.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPatchMapping.java new file mode 100644 index 0000000..3281a3b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPatchMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.example.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code PATCH} requests onto specific handler + * methods. + * * 支持匿名访问 PatchMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousDeleteMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.PATCH) +public @interface AnonymousPatchMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPostMapping.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPostMapping.java new file mode 100644 index 0000000..977de6c --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPostMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.example.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code POST} requests onto specific handler + * methods. + * 支持匿名访问 PostMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousDeleteMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.POST) +public @interface AnonymousPostMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPutMapping.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPutMapping.java new file mode 100644 index 0000000..6fc00b2 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/annotation/rest/AnonymousPutMapping.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.annotation.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.example.annotation.AnonymousAccess; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Annotation for mapping HTTP {@code PUT} requests onto specific handler + * methods. + * * 支持匿名访问 PutMapping + * + * @author liaojinlong + * @see AnonymousGetMapping + * @see AnonymousPostMapping + * @see AnonymousPutMapping + * @see AnonymousDeleteMapping + * @see RequestMapping + */ +@AnonymousAccess +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@RequestMapping(method = RequestMethod.PUT) +public @interface AnonymousPutMapping { + + /** + * Alias for {@link RequestMapping#name}. + */ + @AliasFor(annotation = RequestMapping.class) + String name() default ""; + + /** + * Alias for {@link RequestMapping#value}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] value() default {}; + + /** + * Alias for {@link RequestMapping#path}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + /** + * Alias for {@link RequestMapping#params}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] params() default {}; + + /** + * Alias for {@link RequestMapping#headers}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] headers() default {}; + + /** + * Alias for {@link RequestMapping#consumes}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] consumes() default {}; + + /** + * Alias for {@link RequestMapping#produces}. + */ + @AliasFor(annotation = RequestMapping.class) + String[] produces() default {}; + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitAspect.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitAspect.java new file mode 100644 index 0000000..1e1856d --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitAspect.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.aspect; + +import com.google.common.collect.ImmutableList; +import com.example.annotation.Limit; +import com.example.exception.BadRequestException; +import com.example.utils.RequestHolder; +import com.example.utils.StringUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; + +/** + * @author / + */ +@Aspect +@Component +public class LimitAspect { + + private final RedisTemplate<Object,Object> redisTemplate; + private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class); + + public LimitAspect(RedisTemplate<Object,Object> redisTemplate) { + this.redisTemplate = redisTemplate; + } + + @Pointcut("@annotation(com.example.annotation.Limit)") + public void pointcut() { + } + + @Around("pointcut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + HttpServletRequest request = RequestHolder.getHttpServletRequest(); + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method signatureMethod = signature.getMethod(); + Limit limit = signatureMethod.getAnnotation(Limit.class); + LimitType limitType = limit.limitType(); + String key = limit.key(); + if (StringUtils.isEmpty(key)) { + if (limitType == LimitType.IP) { + key = StringUtils.getIp(request); + } else { + key = signatureMethod.getName(); + } + } + + ImmutableList<Object> keys = ImmutableList.of(StringUtils.join(limit.prefix(), "_", key, "_", request.getRequestURI().replace("/","_"))); + + String luaScript = buildLuaScript(); + RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class); + Number count = redisTemplate.execute(redisScript, keys, limit.count(), limit.period()); + if (null != count && count.intValue() <= limit.count()) { + logger.info("第{}次访问key为 {},描述为 [{}] 的接口", count, keys, limit.name()); + return joinPoint.proceed(); + } else { + throw new BadRequestException("访问次数受限制"); + } + } + + /** + * 限流脚本 + */ + private String buildLuaScript() { + return "local c" + + "\nc = redis.call('get',KEYS[1])" + + "\nif c and tonumber(c) > tonumber(ARGV[1]) then" + + "\nreturn c;" + + "\nend" + + "\nc = redis.call('incr',KEYS[1])" + + "\nif tonumber(c) == 1 then" + + "\nredis.call('expire',KEYS[1],ARGV[2])" + + "\nend" + + "\nreturn c;"; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitType.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitType.java new file mode 100644 index 0000000..0a6deb6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/aspect/LimitType.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.aspect; + +/** + * 限流枚举 + * @author / + */ +public enum LimitType { + // 默认 + CUSTOMER, + // by ip addr + IP +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseDTO.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseDTO.java new file mode 100644 index 0000000..7802007 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseDTO.java @@ -0,0 +1,40 @@ +package com.example.base; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.builder.ToStringBuilder; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.sql.Timestamp; + +/** + * + * 2019年10月24日20:48:53 + */ +@Getter +@Setter +public class BaseDTO implements Serializable { + + private String createBy; + + private String updateBy; + + private Timestamp createTime; + + private Timestamp updateTime; + + @Override + public String toString() { + ToStringBuilder builder = new ToStringBuilder(this); + Field[] fields = this.getClass().getDeclaredFields(); + try { + for (Field f : fields) { + f.setAccessible(true); + builder.append(f.getName(), f.get(this)).append("\n"); + } + } catch (Exception e) { + builder.append("toString builder encounter an error"); + } + return builder.toString(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseEntity.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseEntity.java new file mode 100644 index 0000000..ba31ddf --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseEntity.java @@ -0,0 +1,85 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.base; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.sql.Timestamp; + +/** + * 通用字段, is_del 根据需求自行添加 + * + * @Date 2019年10月24日20:46:32 + */ +@Getter +@Setter +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public class BaseEntity implements Serializable { + + @CreatedBy + @Column(name = "create_by", updatable = false) + @ApiModelProperty(value = "创建人", hidden = true) + private String createBy; + + @LastModifiedBy + @Column(name = "update_by") + @ApiModelProperty(value = "更新人", hidden = true) + private String updateBy; + + @CreationTimestamp + @Column(name = "create_time", updatable = false) + @ApiModelProperty(value = "创建时间", hidden = true) + private Timestamp createTime; + + @UpdateTimestamp + @Column(name = "update_time") + @ApiModelProperty(value = "更新时间", hidden = true) + private Timestamp updateTime; + + /* 分组校验 */ + public @interface Create {} + + /* 分组校验 */ + public @interface Update {} + + @Override + public String toString() { + ToStringBuilder builder = new ToStringBuilder(this); + Field[] fields = this.getClass().getDeclaredFields(); + try { + for (Field f : fields) { + f.setAccessible(true); + builder.append(f.getName(), f.get(this)).append("\n"); + } + } catch (Exception e) { + builder.append("toString builder encounter an error"); + } + return builder.toString(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseMapper.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseMapper.java new file mode 100644 index 0000000..1c2d38a --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/base/BaseMapper.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.base; + +import java.util.List; + + +public interface BaseMapper<D, E> { + + /** + * DTO转Entity + * @param dto / + * @return / + */ + E toEntity(D dto); + + /** + * Entity转DTO + * @param entity / + * @return / + */ + D toDto(E entity); + + /** + * DTO集合转Entity集合 + * @param dtoList / + * @return / + */ + List <E> toEntity(List<D> dtoList); + + /** + * Entity集合转DTO集合 + * @param entityList / + * @return / + */ + List <D> toDto(List<E> entityList); +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/AuditorConfig.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/AuditorConfig.java new file mode 100644 index 0000000..7d1dcbe --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/AuditorConfig.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config; + +import com.example.utils.SecurityUtils; +import org.springframework.data.domain.AuditorAware; +import org.springframework.stereotype.Component; +import java.util.Optional; + +/** + * @description : 设置审计 + * @author : Dong ZhaoYang + * : 2019/10/28 + */ +@Component("auditorAware") +public class AuditorConfig implements AuditorAware<String> { + + /** + * 返回操作员标志信息 + * + * @return / + */ + @Override + public Optional<String> getCurrentAuditor() { + try { + // 这里应根据实际业务情况获取具体信息 + return Optional.of(SecurityUtils.getCurrentUsername()); + }catch (Exception ignored){} + // 用户定时任务,或者无Token调用的情况 + return Optional.of("System"); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElAdminProperties.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElAdminProperties.java new file mode 100644 index 0000000..b7670b3 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElAdminProperties.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * + * @description + * 2021-11-22 + **/ +@Data +@Component +public class ElAdminProperties { + + public static Boolean ipLocal; + + @Value("${ip.local-parsing}") + public void setIpLocal(Boolean ipLocal) { + ElAdminProperties.ipLocal = ipLocal; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElPermissionConfig.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElPermissionConfig.java new file mode 100644 index 0000000..7b7c1e7 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/ElPermissionConfig.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config; + +import com.example.utils.SecurityUtils; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.stereotype.Service; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * + */ +@Service(value = "el") +public class ElPermissionConfig { + + public Boolean check(String ...permissions){ + // 获取当前用户的所有权限 + List<String> elPermissions = SecurityUtils.getCurrentUser().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()); + // 判断当前用户的所有权限是否包含接口上定义的权限 + return elPermissions.contains("admin") || Arrays.stream(permissions).anyMatch(elPermissions::contains); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/FileProperties.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/FileProperties.java new file mode 100644 index 0000000..a1c3aff --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/FileProperties.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config; + +import lombok.Data; +import com.example.utils.ElAdminConstant; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "file") +public class FileProperties { + + /** 文件大小限制 */ + private Long maxSize; + + /** 头像大小限制 */ + private Long avatarMaxSize; + + private ElPath mac; + + private ElPath linux; + + private ElPath windows; + + public ElPath getPath(){ + String os = System.getProperty("os.name"); + if(os.toLowerCase().startsWith(ElAdminConstant.WIN)) { + return windows; + } else if(os.toLowerCase().startsWith(ElAdminConstant.MAC)){ + return mac; + } + return linux; + } + + @Data + public static class ElPath{ + + private String path; + + private String avatar; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RedisConfig.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RedisConfig.java new file mode 100644 index 0000000..d482e83 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RedisConfig.java @@ -0,0 +1,217 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config; + +import cn.hutool.core.lang.Assert; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.serializer.SerializerFeature; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.Cache; +import org.springframework.cache.annotation.CachingConfigurerSupport; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.interceptor.CacheErrorHandler; +import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.RedisSerializer; +import reactor.util.annotation.Nullable; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + + +/** + * + * 2018-11-24 + */ +@Slf4j +@Configuration +@EnableCaching +@ConditionalOnClass(RedisOperations.class) +@EnableConfigurationProperties(RedisProperties.class) +public class RedisConfig extends CachingConfigurerSupport { + + /** + * 设置 redis 数据默认过期时间,默认2小时 + * 设置@cacheable 序列化方式 + */ + @Bean + public RedisCacheConfiguration redisCacheConfiguration(){ + FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); + RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(); + configuration = configuration.serializeValuesWith(RedisSerializationContext. + SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofHours(2)); + return configuration; + } + + @SuppressWarnings("all") + @Bean(name = "redisTemplate") + @ConditionalOnMissingBean(name = "redisTemplate") + public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate<Object, Object> template = new RedisTemplate<>(); + //序列化 + FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); + // value值的序列化采用fastJsonRedisSerializer + template.setValueSerializer(fastJsonRedisSerializer); + template.setHashValueSerializer(fastJsonRedisSerializer); + // 全局开启AutoType,这里方便开发,使用全局的方式 + ParserConfig.getGlobalInstance().setAutoTypeSupport(true); + // 建议使用这种方式,小范围指定白名单 + // ParserConfig.getGlobalInstance().addAccept("com.example.domain"); + // key的序列化采用StringRedisSerializer + template.setKeySerializer(new StringRedisSerializer()); + template.setHashKeySerializer(new StringRedisSerializer()); + template.setConnectionFactory(redisConnectionFactory); + return template; + } + + /** + * 自定义缓存key生成策略,默认将使用该策略 + */ + @Bean + @Override + public KeyGenerator keyGenerator() { + return (target, method, params) -> { + Map<String,Object> container = new HashMap<>(4); + Class<?> targetClassClass = target.getClass(); + // 类地址 + container.put("class",targetClassClass.toGenericString()); + // 方法名称 + container.put("methodName",method.getName()); + // 包名称 + container.put("package",targetClassClass.getPackage()); + // 参数列表 + for (int i = 0; i < params.length; i++) { + container.put(String.valueOf(i),params[i]); + } + // 转为JSON字符串 + String jsonString = JSON.toJSONString(container); + // 做SHA256 Hash计算,得到一个SHA256摘要作为Key + return DigestUtils.sha256Hex(jsonString); + }; + } + + @Bean + @Override + public CacheErrorHandler errorHandler() { + // 异常处理,当Redis发生异常时,打印日志,但是程序正常走 + log.info("初始化 -> [{}]", "Redis CacheErrorHandler"); + return new CacheErrorHandler() { + @Override + public void handleCacheGetError(RuntimeException e, Cache cache, Object key) { + log.error("Redis occur handleCacheGetError:key -> [{}]", key, e); + } + + @Override + public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) { + log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e); + } + + @Override + public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) { + log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e); + } + + @Override + public void handleCacheClearError(RuntimeException e, Cache cache) { + log.error("Redis occur handleCacheClearError:", e); + } + }; + } + +} + +/** + * Value 序列化 + * + * @author / + * @param <T> + */ + class FastJsonRedisSerializer<T> implements RedisSerializer<T> { + + private final Class<T> clazz; + + FastJsonRedisSerializer(Class<T> clazz) { + super(); + this.clazz = clazz; + } + + @Override + public byte[] serialize(T t) { + if (t == null) { + return new byte[0]; + } + return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8); + } + + @Override + public T deserialize(byte[] bytes) { + if (bytes == null || bytes.length <= 0) { + return null; + } + String str = new String(bytes, StandardCharsets.UTF_8); + return JSON.parseObject(str, clazz); + } + +} + +/** + * 重写序列化器 + * + * @author / + */ +class StringRedisSerializer implements RedisSerializer<Object> { + + private final Charset charset; + + StringRedisSerializer() { + this(StandardCharsets.UTF_8); + } + + private StringRedisSerializer(Charset charset) { + Assert.notNull(charset, "Charset must not be null!"); + this.charset = charset; + } + + @Override + public String deserialize(byte[] bytes) { + return (bytes == null ? null : new String(bytes, charset)); + } + + @Override + public @Nullable byte[] serialize(Object object) { + String string = JSON.toJSONString(object); + + if (org.apache.commons.lang3.StringUtils.isBlank(string)) { + return null; + } + string = string.replace("\"", ""); + return string.getBytes(charset); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RsaProperties.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RsaProperties.java new file mode 100644 index 0000000..7490f71 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/RsaProperties.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * + * @website https://el-admin.vip + * @description + * 2020-05-18 + **/ +@Data +@Component +public class RsaProperties { + + public static String privateKey; + + @Value("${rsa.private_key}") + public void setPrivateKey(String privateKey) { + RsaProperties.privateKey = privateKey; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/SwaggerConfig.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/SwaggerConfig.java new file mode 100644 index 0000000..7d0b1c6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/config/SwaggerConfig.java @@ -0,0 +1,148 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config; + +import com.fasterxml.classmate.TypeResolver; +import com.google.common.base.Predicates; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.data.domain.Pageable; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.schema.AlternateTypeRule; +import springfox.documentation.schema.AlternateTypeRuleConvention; +import springfox.documentation.service.*; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.service.contexts.SecurityContext; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; +import java.util.ArrayList; +import java.util.List; +import static com.google.common.collect.Lists.newArrayList; +import static springfox.documentation.schema.AlternateTypeRules.newRule; + +/** + * api页面 /doc.html + * + * 2018-11-23 + */ +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + + @Value("${jwt.header}") + private String tokenHeader; + + @Value("${swagger.enabled}") + private Boolean enabled; + + @Bean + @SuppressWarnings("all") + public Docket createRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .enable(enabled) + .pathMapping("/") + .apiInfo(apiInfo()) + .select() + .paths(Predicates.not(PathSelectors.regex("/error.*"))) + .paths(PathSelectors.any()) + .build() + //添加登陆认证 + .securitySchemes(securitySchemes()) + .securityContexts(securityContexts()); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .description("一个简单且易上手的 Spring boot 后台管理框架") + .title("DNS测绘 接口文档") + .version("2.6") + .build(); + } + + private List<SecurityScheme> securitySchemes() { + //设置请求头信息 + List<SecurityScheme> securitySchemes = new ArrayList<>(); + ApiKey apiKey = new ApiKey(tokenHeader, tokenHeader, "header"); + securitySchemes.add(apiKey); + return securitySchemes; + } + + private List<SecurityContext> securityContexts() { + //设置需要登录认证的路径 + List<SecurityContext> securityContexts = new ArrayList<>(); + // ^(?!auth).*$ 表示所有包含auth的接口不需要使用securitySchemes即不需要带token + // ^标识开始 ()里是一子表达式 ?!/auth表示匹配不是/auth的位置,匹配上则添加请求头,注意路径已/开头 .表示任意字符 *表示前面的字符匹配多次 $标识结束 + securityContexts.add(getContextByPath()); + return securityContexts; + } + + private SecurityContext getContextByPath() { + return SecurityContext.builder() + .securityReferences(defaultAuth()) + .forPaths(PathSelectors.regex("^(?!/auth).*$")) + .build(); + } + + private List<SecurityReference> defaultAuth() { + List<SecurityReference> securityReferences = new ArrayList<>(); + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; + authorizationScopes[0] = authorizationScope; + securityReferences.add(new SecurityReference(tokenHeader, authorizationScopes)); + return securityReferences; + } +} + +/** + * 将Pageable转换展示在swagger中 + */ +@Configuration +class SwaggerDataConfig { + + @Bean + public AlternateTypeRuleConvention pageableConvention(final TypeResolver resolver) { + return new AlternateTypeRuleConvention() { + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } + + @Override + public List<AlternateTypeRule> rules() { + return newArrayList(newRule(resolver.resolve(Pageable.class), resolver.resolve(Page.class))); + } + }; + } + + @ApiModel + @Data + private static class Page { + @ApiModelProperty("页码 (0..N)") + private Integer page; + + @ApiModelProperty("每页显示的数目") + private Integer size; + + @ApiModelProperty("以下列格式排序标准:property[,asc | desc]。 默认排序顺序为升序。 支持多种排序条件:如:id,asc") + private List<String> sort; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadConfigurationException.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadConfigurationException.java new file mode 100644 index 0000000..0ca41ad --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadConfigurationException.java @@ -0,0 +1,98 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.exception; + +/** + * 统一关于错误配置信息 异常 + * + * @author: liaojinlong + * : 2020/6/10 18:06 + */ +public class BadConfigurationException extends RuntimeException { + /** + * Constructs a new runtime exception with {@code null} as its + * detail message. The cause is not initialized, and may subsequently be + * initialized by a call to {@link #initCause}. + */ + public BadConfigurationException() { + super(); + } + + /** + * Constructs a new runtime exception with the specified detail message. + * The cause is not initialized, and may subsequently be initialized by a + * call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for + * later retrieval by the {@link #getMessage()} method. + */ + public BadConfigurationException(String message) { + super(message); + } + + /** + * Constructs a new runtime exception with the specified detail message and + * cause. <p>Note that the detail message associated with + * {@code cause} is <i>not</i> automatically incorporated in + * this runtime exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public BadConfigurationException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new runtime exception with the specified cause and a + * detail message of {@code (cause==null ? null : cause.toString())} + * (which typically contains the class and detail message of + * {@code cause}). This constructor is useful for runtime exceptions + * that are little more than wrappers for other throwables. + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public BadConfigurationException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new runtime exception with the specified detail + * message, cause, suppression enabled or disabled, and writable + * stack trace enabled or disabled. + * + * @param message the detail message. + * @param cause the cause. (A {@code null} value is permitted, + * and indicates that the cause is nonexistent or unknown.) + * @param enableSuppression whether or not suppression is enabled + * or disabled + * @param writableStackTrace whether or not the stack trace should + * be writable + * @since 1.7 + */ + protected BadConfigurationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadRequestException.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadRequestException.java new file mode 100644 index 0000000..e8c7474 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/BadRequestException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.exception; + +import lombok.Getter; +import org.springframework.http.HttpStatus; +import static org.springframework.http.HttpStatus.BAD_REQUEST; + +@Getter +public class BadRequestException extends RuntimeException{ + + private Integer status = BAD_REQUEST.value(); + + public BadRequestException(String msg){ + super(msg); + } + + public BadRequestException(HttpStatus status,String msg){ + super(msg); + this.status = status.value(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityExistException.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityExistException.java new file mode 100644 index 0000000..5af387f --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityExistException.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.exception; + +import org.springframework.util.StringUtils; + + +public class EntityExistException extends RuntimeException { + + public EntityExistException(Class clazz, String field, String val) { + super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val)); + } + + private static String generateMessage(String entity, String field, String val) { + return StringUtils.capitalize(entity) + + " with " + field + " "+ val + " existed"; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityNotFoundException.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityNotFoundException.java new file mode 100644 index 0000000..cdfd771 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/EntityNotFoundException.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.exception; + +import org.springframework.util.StringUtils; + + +public class EntityNotFoundException extends RuntimeException { + + public EntityNotFoundException(Class clazz, String field, String val) { + super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val)); + } + + private static String generateMessage(String entity, String field, String val) { + return StringUtils.capitalize(entity) + + " with " + field + " "+ val + " does not exist"; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/ApiError.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/ApiError.java new file mode 100644 index 0000000..82ec628 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/ApiError.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.exception.handler; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import java.time.LocalDateTime; + + +@Data +class ApiError { + + private Integer status = 400; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime timestamp; + private String message; + + private ApiError() { + timestamp = LocalDateTime.now(); + } + + public static ApiError error(String message){ + ApiError apiError = new ApiError(); + apiError.setMessage(message); + return apiError; + } + + public static ApiError error(Integer status, String message){ + ApiError apiError = new ApiError(); + apiError.setStatus(status); + apiError.setMessage(message); + return apiError; + } +} + + diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/GlobalExceptionHandler.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..ba044d1 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/exception/handler/GlobalExceptionHandler.java @@ -0,0 +1,109 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.exception.handler; + +import com.example.exception.BadRequestException; +import com.example.exception.EntityExistException; +import com.example.exception.EntityNotFoundException; +import com.example.utils.ThrowableUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import java.util.Objects; +import static org.springframework.http.HttpStatus.*; + + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + /** + * 处理所有不可知的异常 + */ + @ExceptionHandler(Throwable.class) + public ResponseEntity<ApiError> handleException(Throwable e){ + // 打印堆栈信息 + log.error(ThrowableUtil.getStackTrace(e)); + return buildResponseEntity(ApiError.error(e.getMessage())); + } + + /** + * BadCredentialsException + */ + @ExceptionHandler(BadCredentialsException.class) + public ResponseEntity<ApiError> badCredentialsException(BadCredentialsException e){ + // 打印堆栈信息 + String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage(); + log.error(message); + return buildResponseEntity(ApiError.error(message)); + } + + /** + * 处理自定义异常 + */ + @ExceptionHandler(value = BadRequestException.class) + public ResponseEntity<ApiError> badRequestException(BadRequestException e) { + // 打印堆栈信息 + log.error(ThrowableUtil.getStackTrace(e)); + return buildResponseEntity(ApiError.error(e.getStatus(),e.getMessage())); + } + + /** + * 处理 EntityExist + */ + @ExceptionHandler(value = EntityExistException.class) + public ResponseEntity<ApiError> entityExistException(EntityExistException e) { + // 打印堆栈信息 + log.error(ThrowableUtil.getStackTrace(e)); + return buildResponseEntity(ApiError.error(e.getMessage())); + } + + /** + * 处理 EntityNotFound + */ + @ExceptionHandler(value = EntityNotFoundException.class) + public ResponseEntity<ApiError> entityNotFoundException(EntityNotFoundException e) { + // 打印堆栈信息 + log.error(ThrowableUtil.getStackTrace(e)); + return buildResponseEntity(ApiError.error(NOT_FOUND.value(),e.getMessage())); + } + + /** + * 处理所有接口数据验证异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){ + // 打印堆栈信息 + log.error(ThrowableUtil.getStackTrace(e)); + String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\."); + String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage(); + String msg = "不能为空"; + if(msg.equals(message)){ + message = str[1] + ":" + message; + } + return buildResponseEntity(ApiError.error(message)); + } + + /** + * 统一返回 + */ + private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) { + return new ResponseEntity<>(apiError, valueOf(apiError.getStatus())); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CacheKey.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CacheKey.java new file mode 100644 index 0000000..8e93877 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CacheKey.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +/** + * @author: liaojinlong + * : 2020/6/11 15:49 + * @apiNote: 关于缓存的Key集合 + */ +public interface CacheKey { + + /** + * 用户 + */ + String USER_ID = "user::id:"; + /** + * 数据 + */ + String DATA_USER = "data::user:"; + /** + * 菜单 + */ + String MENU_ID = "menu::id:"; + String MENU_USER = "menu::user:"; + /** + * 角色授权 + */ + String ROLE_AUTH = "role::auth:"; + /** + * 角色信息 + */ + String ROLE_ID = "role::id:"; + /** + * 部门 + */ + String DEPT_ID = "dept::id:"; + /** + * 岗位 + */ + String JOB_ID = "job::id:"; + /** + * 数据字典 + */ + String DICT_NAME = "dict::name:"; +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CallBack.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CallBack.java new file mode 100644 index 0000000..59a7d0b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CallBack.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.utils; + +/** + * @author: liaojinlong + * : 2020/6/9 17:02 + * @since: 1.0 + * @see {@link SpringContextHolder} + * 针对某些初始化方法,在SpringContextHolder 初始化前时,<br> + * 可提交一个 提交回调任务。<br> + * 在SpringContextHolder 初始化后,进行回调使用 + */ + +public interface CallBack { + /** + * 回调执行方法 + */ + void executor(); + + /** + * 本回调任务名称 + * @return / + */ + default String getCallBackName() { + return Thread.currentThread().getId() + ":" + this.getClass().getName(); + } +} + diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CloseUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CloseUtil.java new file mode 100644 index 0000000..cd515bc --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/CloseUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import java.io.Closeable; + +/** + * + * @website https://el-admin.vip + * @description 用于关闭各种连接,缺啥补啥 + * 2021-03-05 + **/ +public class CloseUtil { + + public static void close(Closeable closeable) { + if (null != closeable) { + try { + closeable.close(); + } catch (Exception e) { + // 静默关闭 + } + } + } + + public static void close(AutoCloseable closeable) { + if (null != closeable) { + try { + closeable.close(); + } catch (Exception e) { + // 静默关闭 + } + } + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/Constant.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/Constant.java new file mode 100644 index 0000000..402403e --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/Constant.java @@ -0,0 +1,62 @@ +package com.example.utils; + +/** + * 常量 + */ +public class Constant { + public static final String DOH = "dns-doh"; + + public static final String DO53 = "dns-do53"; + + public static final String SERVICE = "service"; + + public static final String IP = "ip"; + + public static final String PORT = "port"; + + public static final Integer NONE = 0; + + public static final Integer OPENRDNS = 1; + + public static final Integer FORWARDER = 2; + + public static final Integer FWDRDNS = 3; + + public static final Integer EGRESSRDNS = 4; + + public static final Integer NONSTANDARD = 5; + + public static final String PORT8443 = "8443"; + + public static final String PORT443 = "443"; + + public static final String PORT53 = "53"; + + public static final String DNSTAG = "dns"; + + public static final String DOHTAG = "DNS-DoH"; + + public static final String DO53TAG = "DNS-Do53"; + + public static final String OPENRDNSTAG = "open-rdns"; + + public static final String FORWARDERTAG = "forwarder"; + + public static final String FWDRDNSTAG = "fwd/rdns"; + + public static final String EGRESSRDNSTAG = "egress-dns"; + + public static final String NONSTANDARDTAG = "nonstandard"; + + public static final String PROTOC_TCP = "tcp"; + + public static final String PROTOC_UDP = "udp"; + + public static final String IP_IPV4 = "ipv4"; + + public static final String IP_IPV6 = "ipv6"; + + public static final String POINT = "."; + + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/DateUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/DateUtil.java new file mode 100644 index 0000000..57e9408 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/DateUtil.java @@ -0,0 +1,160 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.utils; + +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +/** + * @author: liaojinlong + * : 2020/6/11 16:28 + * @apiNote: JDK 8 新日期类 格式化与字符串转换 工具类 + */ +public class DateUtil { + + public static final DateTimeFormatter DFY_MD_HMS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + public static final DateTimeFormatter DFY_MD = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + /** + * LocalDateTime 转时间戳 + * + * @param localDateTime / + * @return / + */ + public static Long getTimeStamp(LocalDateTime localDateTime) { + return localDateTime.atZone(ZoneId.systemDefault()).toEpochSecond(); + } + + /** + * 时间戳转LocalDateTime + * + * @param timeStamp / + * @return / + */ + public static LocalDateTime fromTimeStamp(Long timeStamp) { + return LocalDateTime.ofEpochSecond(timeStamp, 0, OffsetDateTime.now().getOffset()); + } + + /** + * LocalDateTime 转 Date + * Jdk8 后 不推荐使用 {@link Date} Date + * + * @param localDateTime / + * @return / + */ + public static Date toDate(LocalDateTime localDateTime) { + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); + } + + /** + * LocalDate 转 Date + * Jdk8 后 不推荐使用 {@link Date} Date + * + * @param localDate / + * @return / + */ + public static Date toDate(LocalDate localDate) { + return toDate(localDate.atTime(LocalTime.now(ZoneId.systemDefault()))); + } + + + /** + * Date转 LocalDateTime + * Jdk8 后 不推荐使用 {@link Date} Date + * + * @param date / + * @return / + */ + public static LocalDateTime toLocalDateTime(Date date) { + return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); + } + + /** + * 日期 格式化 + * + * @param localDateTime / + * @param patten / + * @return / + */ + public static String localDateTimeFormat(LocalDateTime localDateTime, String patten) { + DateTimeFormatter df = DateTimeFormatter.ofPattern(patten); + return df.format(localDateTime); + } + + /** + * 日期 格式化 + * + * @param localDateTime / + * @param df / + * @return / + */ + public static String localDateTimeFormat(LocalDateTime localDateTime, DateTimeFormatter df) { + return df.format(localDateTime); + } + + /** + * 日期格式化 yyyy-MM-dd HH:mm:ss + * + * @param localDateTime / + * @return / + */ + public static String localDateTimeFormatyMdHms(LocalDateTime localDateTime) { + return DFY_MD_HMS.format(localDateTime); + } + + /** + * 日期格式化 yyyy-MM-dd + * + * @param localDateTime / + * @return / + */ + public String localDateTimeFormatyMd(LocalDateTime localDateTime) { + return DFY_MD.format(localDateTime); + } + + /** + * 字符串转 LocalDateTime ,字符串格式 yyyy-MM-dd + * + * @param localDateTime / + * @return / + */ + public static LocalDateTime parseLocalDateTimeFormat(String localDateTime, String pattern) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern); + return LocalDateTime.from(dateTimeFormatter.parse(localDateTime)); + } + + /** + * 字符串转 LocalDateTime ,字符串格式 yyyy-MM-dd + * + * @param localDateTime / + * @return / + */ + public static LocalDateTime parseLocalDateTimeFormat(String localDateTime, DateTimeFormatter dateTimeFormatter) { + return LocalDateTime.from(dateTimeFormatter.parse(localDateTime)); + } + + /** + * 字符串转 LocalDateTime ,字符串格式 yyyy-MM-dd HH:mm:ss + * + * @param localDateTime / + * @return / + */ + public static LocalDateTime parseLocalDateTimeFormatyMdHms(String localDateTime) { + return LocalDateTime.from(DFY_MD_HMS.parse(localDateTime)); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ElAdminConstant.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ElAdminConstant.java new file mode 100644 index 0000000..f46ff3b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ElAdminConstant.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import java.util.Arrays; +import java.util.List; + +/** + * 常用静态常量 + * + * + * 2018-12-26 + */ +public class ElAdminConstant { + + private ElAdminConstant() { + throw new IllegalStateException("Utility class"); + } + + /** + * 用于IP定位转换 + */ + public static final String REGION = "内网IP|内网IP"; + /** + * win 系统 + */ + public static final String WIN = "win"; + + /** + * mac 系统 + */ + public static final String MAC = "mac"; + + public static final List<String> openRdnsLabels = Arrays.asList("DNS", "DNS-Do53", "open-rdns"); + + public static final List<String> forwarderLabels = Arrays.asList("DNS", "DNS-Do53", "forwarder"); + + public static final List<String> fwdRdnsLabels = Arrays.asList("DNS", "DNS-Do53", "fwd/rdns"); + + public static final List<String> egressDnsLabels = Arrays.asList("DNS", "DNS-Do53", "egress-dns"); + + public static final List<String> nonstandardLabels = Arrays.asList("DNS", "DNS-Do53", "nonstandard"); + + public static final List<String> dnsLabels = Arrays.asList("DNS"); + + public static final List<String> dohLabels = Arrays.asList("DNS","DNS-DoH"); + + public static final List<String> do53Labels = Arrays.asList(new String[]{"DNS","DNS-Do53"}); + + /** + * 常用接口 + */ + public static class Url { + // IP归属地查询 + public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp?ip=%s&json=true"; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/EncryptUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/EncryptUtils.java new file mode 100644 index 0000000..6ee5a49 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/EncryptUtils.java @@ -0,0 +1,100 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.IvParameterSpec; +import java.nio.charset.StandardCharsets; + +/** + * 加密 + * + * 2018-11-23 + */ + +public class EncryptUtils { + + private static final String STR_PARAM = "Passw0rd"; + + private static Cipher cipher; + + private static final IvParameterSpec IV = new IvParameterSpec(STR_PARAM.getBytes(StandardCharsets.UTF_8)); + + private static DESKeySpec getDesKeySpec(String source) throws Exception { + if (source == null || source.length() == 0){ + return null; + } + cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); + String strKey = "Passw0rd"; + return new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8)); + } + + /** + * 对称加密 + */ + public static String desEncrypt(String source) throws Exception { + DESKeySpec desKeySpec = getDesKeySpec(source); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + SecretKey secretKey = keyFactory.generateSecret(desKeySpec); + cipher.init(Cipher.ENCRYPT_MODE, secretKey, IV); + return byte2hex( + cipher.doFinal(source.getBytes(StandardCharsets.UTF_8))).toUpperCase(); + } + + /** + * 对称解密 + */ + public static String desDecrypt(String source) throws Exception { + byte[] src = hex2byte(source.getBytes(StandardCharsets.UTF_8)); + DESKeySpec desKeySpec = getDesKeySpec(source); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + SecretKey secretKey = keyFactory.generateSecret(desKeySpec); + cipher.init(Cipher.DECRYPT_MODE, secretKey, IV); + byte[] retByte = cipher.doFinal(src); + return new String(retByte); + } + + private static String byte2hex(byte[] inStr) { + String stmp; + StringBuilder out = new StringBuilder(inStr.length * 2); + for (byte b : inStr) { + stmp = Integer.toHexString(b & 0xFF); + if (stmp.length() == 1) { + // 如果是0至F的单位字符串,则添加0 + out.append("0").append(stmp); + } else { + out.append(stmp); + } + } + return out.toString(); + } + + private static byte[] hex2byte(byte[] b) { + int size = 2; + if ((b.length % size) != 0){ + throw new IllegalArgumentException("长度不是偶数"); + } + byte[] b2 = new byte[b.length / 2]; + for (int n = 0; n < b.length; n += size) { + String item = new String(b, n, 2); + b2[n / 2] = (byte) Integer.parseInt(item, 16); + } + return b2; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/FileUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/FileUtil.java new file mode 100644 index 0000000..dc209a9 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/FileUtil.java @@ -0,0 +1,356 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.poi.excel.BigExcelWriter; +import cn.hutool.poi.excel.ExcelUtil; +import com.example.exception.BadRequestException; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.security.MessageDigest; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * File工具类,扩展 hutool 工具包 + * + * + * 2018-12-27 + */ +public class FileUtil extends cn.hutool.core.io.FileUtil { + + private static final Logger log = LoggerFactory.getLogger(FileUtil.class); + + /** + * 系统临时目录 + * <br> + * windows 包含路径分割符,但Linux 不包含, + * 在windows \\==\ 前提下, + * 为安全起见 同意拼装 路径分割符, + * <pre> + * java.io.tmpdir + * windows : C:\Users/xxx\AppData\Local\Temp\ + * linux: /temp + * </pre> + */ + public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator; + /** + * 定义GB的计算常量 + */ + private static final int GB = 1024 * 1024 * 1024; + /** + * 定义MB的计算常量 + */ + private static final int MB = 1024 * 1024; + /** + * 定义KB的计算常量 + */ + private static final int KB = 1024; + + /** + * 格式化小数 + */ + private static final DecimalFormat DF = new DecimalFormat("0.00"); + + public static final String IMAGE = "图片"; + public static final String TXT = "文档"; + public static final String MUSIC = "音乐"; + public static final String VIDEO = "视频"; + public static final String OTHER = "其他"; + + + /** + * MultipartFile转File + */ + public static File toFile(MultipartFile multipartFile) { + // 获取文件名 + String fileName = multipartFile.getOriginalFilename(); + // 获取文件后缀 + String prefix = "." + getExtensionName(fileName); + File file = null; + try { + // 用uuid作为文件名,防止生成的临时文件重复 + file = new File(SYS_TEM_DIR + IdUtil.simpleUUID() + prefix); + // MultipartFile to File + multipartFile.transferTo(file); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + return file; + } + + /** + * 获取文件扩展名,不带 . + */ + public static String getExtensionName(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot > -1) && (dot < (filename.length() - 1))) { + return filename.substring(dot + 1); + } + } + return filename; + } + + /** + * Java文件操作 获取不带扩展名的文件名 + */ + public static String getFileNameNoEx(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot > -1) && (dot < (filename.length()))) { + return filename.substring(0, dot); + } + } + return filename; + } + + /** + * 文件大小转换 + */ + public static String getSize(long size) { + String resultSize; + if (size / GB >= 1) { + //如果当前Byte的值大于等于1GB + resultSize = DF.format(size / (float) GB) + "GB "; + } else if (size / MB >= 1) { + //如果当前Byte的值大于等于1MB + resultSize = DF.format(size / (float) MB) + "MB "; + } else if (size / KB >= 1) { + //如果当前Byte的值大于等于1KB + resultSize = DF.format(size / (float) KB) + "KB "; + } else { + resultSize = size + "B "; + } + return resultSize; + } + + /** + * inputStream 转 File + */ + static File inputStreamToFile(InputStream ins, String name){ + File file = new File(SYS_TEM_DIR + name); + if (file.exists()) { + return file; + } + OutputStream os = null; + try { + os = new FileOutputStream(file); + int bytesRead; + int len = 8192; + byte[] buffer = new byte[len]; + while ((bytesRead = ins.read(buffer, 0, len)) != -1) { + os.write(buffer, 0, bytesRead); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + CloseUtil.close(os); + CloseUtil.close(ins); + } + return file; + } + + /** + * 将文件名解析成文件的上传路径 + */ + public static File upload(MultipartFile file, String filePath) { + Date date = new Date(); + SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS"); + String name = getFileNameNoEx(file.getOriginalFilename()); + String suffix = getExtensionName(file.getOriginalFilename()); + String nowStr = "-" + format.format(date); + try { + String fileName = name + nowStr + "." + suffix; + String path = filePath + fileName; + // getCanonicalFile 可解析正确各种路径 + File dest = new File(path).getCanonicalFile(); + // 检测是否存在目录 + if (!dest.getParentFile().exists()) { + if (!dest.getParentFile().mkdirs()) { + System.out.println("was not successful."); + } + } + // 文件写入 + file.transferTo(dest); + return dest; + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return null; + } + + /** + * 导出excel + */ + public static void downloadExcel(List<Map<String, Object>> list, HttpServletResponse response) throws IOException { + String tempPath = SYS_TEM_DIR + IdUtil.fastSimpleUUID() + ".xlsx"; + File file = new File(tempPath); + BigExcelWriter writer = ExcelUtil.getBigWriter(file); + // 一次性写出内容,使用默认样式,强制输出标题 + writer.write(list, true); + SXSSFSheet sheet = (SXSSFSheet)writer.getSheet(); + //上面需要强转SXSSFSheet 不然没有trackAllColumnsForAutoSizing方法 + sheet.trackAllColumnsForAutoSizing(); + //列宽自适应 + writer.autoSizeColumnAll(); + //response为HttpServletResponse对象 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); + //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码 + response.setHeader("Content-Disposition", "attachment;filename=file.xlsx"); + ServletOutputStream out = response.getOutputStream(); + // 终止后删除临时文件 + file.deleteOnExit(); + writer.flush(out, true); + //此处记得关闭输出Servlet流 + IoUtil.close(out); + } + + public static String getFileType(String type) { + String documents = "txt doc pdf ppt pps xlsx xls docx"; + String music = "mp3 wav wma mpa ram ra aac aif m4a"; + String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg"; + String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg"; + if (image.contains(type)) { + return IMAGE; + } else if (documents.contains(type)) { + return TXT; + } else if (music.contains(type)) { + return MUSIC; + } else if (video.contains(type)) { + return VIDEO; + } else { + return OTHER; + } + } + + public static void checkSize(long maxSize, long size) { + // 1M + int len = 1024 * 1024; + if (size > (maxSize * len)) { + throw new BadRequestException("文件超出规定大小:" + maxSize + "MB"); + } + } + + /** + * 判断两个文件是否相同 + */ + public static boolean check(File file1, File file2) { + String img1Md5 = getMd5(file1); + String img2Md5 = getMd5(file2); + if(img1Md5 != null){ + return img1Md5.equals(img2Md5); + } + return false; + } + + /** + * 判断两个文件是否相同 + */ + public static boolean check(String file1Md5, String file2Md5) { + return file1Md5.equals(file2Md5); + } + + private static byte[] getByte(File file) { + // 得到文件长度 + byte[] b = new byte[(int) file.length()]; + InputStream in = null; + try { + in = new FileInputStream(file); + try { + System.out.println(in.read(b)); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } finally { + CloseUtil.close(in); + } + return b; + } + + private static String getMd5(byte[] bytes) { + // 16进制字符 + char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + try { + MessageDigest mdTemp = MessageDigest.getInstance("MD5"); + mdTemp.update(bytes); + byte[] md = mdTemp.digest(); + int j = md.length; + char[] str = new char[j * 2]; + int k = 0; + // 移位 输出字符串 + for (byte byte0 : md) { + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + } + return new String(str); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return null; + } + + /** + * 下载文件 + * + * @param request / + * @param response / + * @param file / + */ + public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) { + response.setCharacterEncoding(request.getCharacterEncoding()); + response.setContentType("application/octet-stream"); + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + response.setHeader("Content-Disposition", "attachment; filename=" + file.getName()); + IOUtils.copy(fis, response.getOutputStream()); + response.flushBuffer(); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + if (fis != null) { + try { + fis.close(); + if (deleteOnExit) { + file.deleteOnExit(); + } + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + } + } + + public static String getMd5(File file) { + return getMd5(getByte(file)); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/PageUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/PageUtil.java new file mode 100644 index 0000000..5bea120 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/PageUtil.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import org.springframework.data.domain.Page; +import java.util.*; + +/** + * 分页工具 + * + * 2018-12-10 + */ +public class PageUtil extends cn.hutool.core.util.PageUtil { + + /** + * List 分页 + */ + public static List toPage(int page, int size , List list) { + int fromIndex = page * size; + int toIndex = page * size + size; + if(fromIndex > list.size()){ + return new ArrayList(); + } else if(toIndex >= list.size()) { + return list.subList(fromIndex,list.size()); + } else { + return list.subList(fromIndex,toIndex); + } + } + + /** + * Page 数据处理,预防redis反序列化报错 + */ + public static Map<String,Object> toPage(Page page) { + Map<String,Object> map = new LinkedHashMap<>(2); + map.put("content",page.getContent()); + map.put("totalElements",page.getTotalElements()); + return map; + } + + /** + * 自定义分页 + */ + public static Map<String,Object> toPage(Object object, Object totalElements) { + Map<String,Object> map = new LinkedHashMap<>(2); + map.put("content",object); + map.put("totalElements",totalElements); + return map; + } + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/QueryHelp.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/QueryHelp.java new file mode 100644 index 0000000..e9cf239 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/QueryHelp.java @@ -0,0 +1,208 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import com.example.annotation.DataPermission; +import com.example.annotation.Query; +import javax.persistence.criteria.*; +import java.lang.reflect.Field; +import java.util.*; + +/** + * + * 2019-6-4 14:59:48 + */ +@Slf4j +@SuppressWarnings({"unchecked","all"}) +public class QueryHelp { + + public static <R, Q> Predicate getPredicate(Root<R> root, Q query, CriteriaBuilder cb) { + List<Predicate> list = new ArrayList<>(); + if(query == null){ + return cb.and(list.toArray(new Predicate[0])); + } + // 数据权限验证 + DataPermission permission = query.getClass().getAnnotation(DataPermission.class); + if(permission != null){ + // 获取数据权限 + List<Long> dataScopes = SecurityUtils.getCurrentUserDataScope(); + if(CollectionUtil.isNotEmpty(dataScopes)){ + if(StringUtils.isNotBlank(permission.joinName()) && StringUtils.isNotBlank(permission.fieldName())) { + Join join = root.join(permission.joinName(), JoinType.LEFT); + list.add(getExpression(permission.fieldName(),join, root).in(dataScopes)); + } else if (StringUtils.isBlank(permission.joinName()) && StringUtils.isNotBlank(permission.fieldName())) { + list.add(getExpression(permission.fieldName(),null, root).in(dataScopes)); + } + } + } + try { + List<Field> fields = getAllFields(query.getClass(), new ArrayList<>()); + for (Field field : fields) { + boolean accessible = field.isAccessible(); + // 设置对象的访问权限,保证对private的属性的访 + field.setAccessible(true); + Query q = field.getAnnotation(Query.class); + if (q != null) { + String propName = q.propName(); + String joinName = q.joinName(); + String blurry = q.blurry(); + String attributeName = isBlank(propName) ? field.getName() : propName; + Class<?> fieldType = field.getType(); + Object val = field.get(query); + if (ObjectUtil.isNull(val) || "".equals(val)) { + continue; + } + Join join = null; + // 模糊多字段 + if (ObjectUtil.isNotEmpty(blurry)) { + String[] blurrys = blurry.split(","); + List<Predicate> orPredicate = new ArrayList<>(); + for (String s : blurrys) { + orPredicate.add(cb.like(root.get(s) + .as(String.class), "%" + val.toString() + "%")); + } + Predicate[] p = new Predicate[orPredicate.size()]; + list.add(cb.or(orPredicate.toArray(p))); + continue; + } + if (ObjectUtil.isNotEmpty(joinName)) { + String[] joinNames = joinName.split(">"); + for (String name : joinNames) { + switch (q.join()) { + case LEFT: + if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){ + join = join.join(name, JoinType.LEFT); + } else { + join = root.join(name, JoinType.LEFT); + } + break; + case RIGHT: + if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){ + join = join.join(name, JoinType.RIGHT); + } else { + join = root.join(name, JoinType.RIGHT); + } + break; + case INNER: + if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){ + join = join.join(name, JoinType.INNER); + } else { + join = root.join(name, JoinType.INNER); + } + break; + default: break; + } + } + } + switch (q.type()) { + case EQUAL: + list.add(cb.equal(getExpression(attributeName,join,root) + .as((Class<? extends Comparable>) fieldType),val)); + break; + case GREATER_THAN: + list.add(cb.greaterThanOrEqualTo(getExpression(attributeName,join,root) + .as((Class<? extends Comparable>) fieldType), (Comparable) val)); + break; + case LESS_THAN: + list.add(cb.lessThanOrEqualTo(getExpression(attributeName,join,root) + .as((Class<? extends Comparable>) fieldType), (Comparable) val)); + break; + case LESS_THAN_NQ: + list.add(cb.lessThan(getExpression(attributeName,join,root) + .as((Class<? extends Comparable>) fieldType), (Comparable) val)); + break; + case INNER_LIKE: + list.add(cb.like(getExpression(attributeName,join,root) + .as(String.class), "%" + val.toString() + "%")); + break; + case LEFT_LIKE: + list.add(cb.like(getExpression(attributeName,join,root) + .as(String.class), "%" + val.toString())); + break; + case RIGHT_LIKE: + list.add(cb.like(getExpression(attributeName,join,root) + .as(String.class), val.toString() + "%")); + break; + case IN: + if (CollUtil.isNotEmpty((Collection<Object>)val)) { + list.add(getExpression(attributeName,join,root).in((Collection<Object>) val)); + } + break; + case NOT_IN: + if (CollUtil.isNotEmpty((Collection<Object>)val)) { + list.add(getExpression(attributeName,join,root).in((Collection<Object>) val).not()); + } + break; + case NOT_EQUAL: + list.add(cb.notEqual(getExpression(attributeName,join,root), val)); + break; + case NOT_NULL: + list.add(cb.isNotNull(getExpression(attributeName,join,root))); + break; + case IS_NULL: + list.add(cb.isNull(getExpression(attributeName,join,root))); + break; + case BETWEEN: + List<Object> between = new ArrayList<>((List<Object>)val); + list.add(cb.between(getExpression(attributeName, join, root).as((Class<? extends Comparable>) between.get(0).getClass()), + (Comparable) between.get(0), (Comparable) between.get(1))); + break; + default: break; + } + } + field.setAccessible(accessible); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + int size = list.size(); + return cb.and(list.toArray(new Predicate[size])); + } + + @SuppressWarnings("unchecked") + private static <T, R> Expression<T> getExpression(String attributeName, Join join, Root<R> root) { + if (ObjectUtil.isNotEmpty(join)) { + return join.get(attributeName); + } else { + return root.get(attributeName); + } + } + + private static boolean isBlank(final CharSequence cs) { + int strLen; + if (cs == null || (strLen = cs.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + return true; + } + + public static List<Field> getAllFields(Class clazz, List<Field> fields) { + if (clazz != null) { + fields.addAll(Arrays.asList(clazz.getDeclaredFields())); + getAllFields(clazz.getSuperclass(), fields); + } + return fields; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RedisUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RedisUtils.java new file mode 100644 index 0000000..4de0949 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RedisUtils.java @@ -0,0 +1,708 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.*; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * @author / + */ +@Component +@SuppressWarnings({"unchecked", "all"}) +public class RedisUtils { + private static final Logger log = LoggerFactory.getLogger(RedisUtils.class); + private RedisTemplate<Object, Object> redisTemplate; + @Value("${jwt.online-key}") + private String onlineKey; + + public RedisUtils(RedisTemplate<Object, Object> redisTemplate) { + this.redisTemplate = redisTemplate; + } + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + */ + public boolean expire(String key, long time) { + try { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + return true; + } + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + * @param timeUnit 单位 + */ + public boolean expire(String key, long time, TimeUnit timeUnit) { + try { + if (time > 0) { + redisTemplate.expire(key, time, timeUnit); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + return true; + } + + /** + * 根据 key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public long getExpire(Object key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + /** + * 查找匹配key + * + * @param pattern key + * @return / + */ + public List<String> scan(String pattern) { + ScanOptions options = ScanOptions.scanOptions().match(pattern).build(); + RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); + RedisConnection rc = Objects.requireNonNull(factory).getConnection(); + Cursor<byte[]> cursor = rc.scan(options); + List<String> result = new ArrayList<>(); + while (cursor.hasNext()) { + result.add(new String(cursor.next())); + } + try { + RedisConnectionUtils.releaseConnection(rc, factory); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return result; + } + + /** + * 分页查询 key + * + * @param patternKey key + * @param page 页码 + * @param size 每页数目 + * @return / + */ + public List<String> findKeysForPage(String patternKey, int page, int size) { + ScanOptions options = ScanOptions.scanOptions().match(patternKey).build(); + RedisConnectionFactory factory = redisTemplate.getConnectionFactory(); + RedisConnection rc = Objects.requireNonNull(factory).getConnection(); + Cursor<byte[]> cursor = rc.scan(options); + List<String> result = new ArrayList<>(size); + int tmpIndex = 0; + int fromIndex = page * size; + int toIndex = page * size + size; + while (cursor.hasNext()) { + if (tmpIndex >= fromIndex && tmpIndex < toIndex) { + result.add(new String(cursor.next())); + tmpIndex++; + continue; + } + // 获取到满足条件的数据后,就可以退出了 + if (tmpIndex >= toIndex) { + break; + } + tmpIndex++; + cursor.next(); + } + try { + RedisConnectionUtils.releaseConnection(rc, factory); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return result; + } + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public boolean hasKey(String key) { + try { + return redisTemplate.hasKey(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + public void del(String... keys) { + if (keys != null && keys.length > 0) { + if (keys.length == 1) { + boolean result = redisTemplate.delete(keys[0]); + log.debug("--------------------------------------------"); + log.debug(new StringBuilder("删除缓存:").append(keys[0]).append(",结果:").append(result).toString()); + log.debug("--------------------------------------------"); + } else { + Set<Object> keySet = new HashSet<>(); + for (String key : keys) { + keySet.addAll(redisTemplate.keys(key)); + } + long count = redisTemplate.delete(keySet); + log.debug("--------------------------------------------"); + log.debug("成功删除缓存:" + keySet.toString()); + log.debug("缓存删除数量:" + count + "个"); + log.debug("--------------------------------------------"); + } + } + } + + // ============================String============================= + + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public Object get(String key) { + return key == null ? null : redisTemplate.opsForValue().get(key); + } + + /** + * 批量获取 + * + * @param keys + * @return + */ + public List<Object> multiGet(List<String> keys) { + List list = redisTemplate.opsForValue().multiGet(Sets.newHashSet(keys)); + List resultList = Lists.newArrayList(); + Optional.ofNullable(list).ifPresent(e-> list.forEach(ele-> Optional.ofNullable(ele).ifPresent(resultList::add))); + return resultList; + } + + /** + * 普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public boolean set(String key, Object value) { + try { + redisTemplate.opsForValue().set(key, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public boolean set(String key, Object value, long time) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间 + * @param timeUnit 类型 + * @return true成功 false 失败 + */ + public boolean set(String key, Object value, long time, TimeUnit timeUnit) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, timeUnit); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + // ================================Map================================= + + /** + * HashGet + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return 值 + */ + public Object hget(String key, String item) { + return redisTemplate.opsForHash().get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public Map<Object, Object> hmget(String key) { + return redisTemplate.opsForHash().entries(key); + + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map<String, Object> map) { + try { + redisTemplate.opsForHash().putAll(key, map); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * HashSet 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public boolean hmset(String key, Map<String, Object> map, long time) { + try { + redisTemplate.opsForHash().putAll(key, map); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value) { + try { + redisTemplate.opsForHash().put(key, item, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value, long time) { + try { + redisTemplate.opsForHash().put(key, item, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 删除hash表中的值 + * + * @param key 键 不能为null + * @param item 项 可以使多个 不能为null + */ + public void hdel(String key, Object... item) { + redisTemplate.opsForHash().delete(key, item); + } + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public boolean hHasKey(String key, String item) { + return redisTemplate.opsForHash().hasKey(key, item); + } + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + * @return + */ + public double hincr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, by); + } + + /** + * hash递减 + * + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + * @return + */ + public double hdecr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, -by); + } + + // ============================set============================= + + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + * @return + */ + public Set<Object> sGet(String key) { + try { + return redisTemplate.opsForSet().members(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 根据value从一个set中查询,是否存在 + * + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public boolean sHasKey(String key, Object value) { + try { + return redisTemplate.opsForSet().isMember(key, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将数据放入set缓存 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSet(String key, Object... values) { + try { + return redisTemplate.opsForSet().add(key, values); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 将set数据放入缓存 + * + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSetAndTime(String key, long time, Object... values) { + try { + Long count = redisTemplate.opsForSet().add(key, values); + if (time > 0) { + expire(key, time); + } + return count; + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 获取set缓存的长度 + * + * @param key 键 + * @return + */ + public long sGetSetSize(String key) { + try { + return redisTemplate.opsForSet().size(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 移除值为value的 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + */ + public long setRemove(String key, Object... values) { + try { + Long count = redisTemplate.opsForSet().remove(key, values); + return count; + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + // ===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return + */ + public List<Object> lGet(String key, long start, long end) { + try { + return redisTemplate.opsForList().range(key, start, end); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public long lGetListSize(String key) { + try { + return redisTemplate.opsForList().size(key); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Object lGetIndex(String key, long index) { + try { + return redisTemplate.opsForList().index(key, index); + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, Object value) { + try { + redisTemplate.opsForList().rightPush(key, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, Object value, long time) { + try { + redisTemplate.opsForList().rightPush(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, List<Object> value) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List<Object> value, long time) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 根据索引修改list中的某条数据 + * + * @param key 键 + * @param index 索引 + * @param value 值 + * @return / + */ + public boolean lUpdateIndex(String key, long index, Object value) { + try { + redisTemplate.opsForList().set(key, index, value); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 移除N个值为value + * + * @param key 键 + * @param count 移除多少个 + * @param value 值 + * @return 移除的个数 + */ + public long lRemove(String key, long count, Object value) { + try { + return redisTemplate.opsForList().remove(key, count, value); + } catch (Exception e) { + log.error(e.getMessage(), e); + return 0; + } + } + + /** + * @param prefix 前缀 + * @param ids id + */ + public void delByKeys(String prefix, Set<Long> ids) { + Set<Object> keys = new HashSet<>(); + for (Long id : ids) { + keys.addAll(redisTemplate.keys(new StringBuffer(prefix).append(id).toString())); + } + long count = redisTemplate.delete(keys); + // 此处提示可自行删除 + log.debug("--------------------------------------------"); + log.debug("成功删除缓存:" + keys.toString()); + log.debug("缓存删除数量:" + count + "个"); + log.debug("--------------------------------------------"); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RequestHolder.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RequestHolder.java new file mode 100644 index 0000000..09764e4 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RequestHolder.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import javax.servlet.http.HttpServletRequest; +import java.util.Objects; + +/** + * 获取 HttpServletRequest + * + * 2018-11-24 + */ +public class RequestHolder { + + public static HttpServletRequest getHttpServletRequest() { + return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RsaUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RsaUtils.java new file mode 100644 index 0000000..4611a15 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/RsaUtils.java @@ -0,0 +1,198 @@ +package com.example.utils; + +import org.apache.commons.codec.binary.Base64; +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** + * @author https://www.cnblogs.com/nihaorz/p/10690643.html + * @description Rsa 工具类,公钥私钥生成,加解密 + * 2020-05-18 + **/ +public class RsaUtils { + + private static final String SRC = "123456"; + + public static void main(String[] args) throws Exception { + System.out.println("\n"); + RsaKeyPair keyPair = generateKeyPair(); + System.out.println("公钥:" + keyPair.getPublicKey()); + System.out.println("私钥:" + keyPair.getPrivateKey()); + System.out.println("\n"); + test1(keyPair); + System.out.println("\n"); + test2(keyPair); + System.out.println("\n"); + } + + /** + * 公钥加密私钥解密 + */ + private static void test1(RsaKeyPair keyPair) throws Exception { + System.out.println("***************** 公钥加密私钥解密开始 *****************"); + String text1 = encryptByPublicKey(keyPair.getPublicKey(), RsaUtils.SRC); + String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1); + System.out.println("加密前:" + RsaUtils.SRC); + System.out.println("加密后:" + text1); + System.out.println("解密后:" + text2); + if (RsaUtils.SRC.equals(text2)) { + System.out.println("解密字符串和原始字符串一致,解密成功"); + } else { + System.out.println("解密字符串和原始字符串不一致,解密失败"); + } + System.out.println("***************** 公钥加密私钥解密结束 *****************"); + } + + /** + * 私钥加密公钥解密 + * @throws Exception / + */ + private static void test2(RsaKeyPair keyPair) throws Exception { + System.out.println("***************** 私钥加密公钥解密开始 *****************"); + String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), RsaUtils.SRC); + String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1); + System.out.println("加密前:" + RsaUtils.SRC); + System.out.println("加密后:" + text1); + System.out.println("解密后:" + text2); + if (RsaUtils.SRC.equals(text2)) { + System.out.println("解密字符串和原始字符串一致,解密成功"); + } else { + System.out.println("解密字符串和原始字符串不一致,解密失败"); + } + System.out.println("***************** 私钥加密公钥解密结束 *****************"); + } + + /** + * 公钥解密 + * + * @param publicKeyText 公钥 + * @param text 待解密的信息 + * @return / + * @throws Exception / + */ + public static String decryptByPublicKey(String publicKeyText, String text) throws Exception { + X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText)); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + byte[] result = doLongerCipherFinal(Cipher.DECRYPT_MODE, cipher, Base64.decodeBase64(text)); + return new String(result); + } + + /** + * 私钥加密 + * + * @param privateKeyText 私钥 + * @param text 待加密的信息 + * @return / + * @throws Exception / + */ + public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception { + PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText)); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + byte[] result = doLongerCipherFinal(Cipher.ENCRYPT_MODE, cipher, text.getBytes()); + return Base64.encodeBase64String(result); + } + + /** + * 私钥解密 + * + * @param privateKeyText 私钥 + * @param text 待解密的文本 + * @return / + * @throws Exception / + */ + public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception { + PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText)); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + byte[] result = doLongerCipherFinal(Cipher.DECRYPT_MODE, cipher, Base64.decodeBase64(text)); + return new String(result); + } + + /** + * 公钥加密 + * + * @param publicKeyText 公钥 + * @param text 待加密的文本 + * @return / + */ + public static String encryptByPublicKey(String publicKeyText, String text) throws Exception { + X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText)); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + byte[] result = doLongerCipherFinal(Cipher.ENCRYPT_MODE, cipher, text.getBytes()); + return Base64.encodeBase64String(result); + } + + private static byte[] doLongerCipherFinal(int opMode,Cipher cipher, byte[] source) throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + if (opMode == Cipher.DECRYPT_MODE) { + out.write(cipher.doFinal(source)); + } else { + int offset = 0; + int totalSize = source.length; + while (totalSize - offset > 0) { + int size = Math.min(cipher.getOutputSize(0) - 11, totalSize - offset); + out.write(cipher.doFinal(source, offset, size)); + offset += size; + } + } + out.close(); + return out.toByteArray(); + } + + /** + * 构建RSA密钥对 + * + * @return / + * @throws NoSuchAlgorithmException / + */ + public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(1024); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); + RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); + String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded()); + String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded()); + return new RsaKeyPair(publicKeyString, privateKeyString); + } + + + /** + * RSA密钥对对象 + */ + public static class RsaKeyPair { + + private final String publicKey; + private final String privateKey; + + public RsaKeyPair(String publicKey, String privateKey) { + this.publicKey = publicKey; + this.privateKey = privateKey; + } + + public String getPublicKey() { + return publicKey; + } + + public String getPrivateKey() { + return privateKey; + } + + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SecurityUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SecurityUtils.java new file mode 100644 index 0000000..e263130 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SecurityUtils.java @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.example.utils.enums.DataScopeEnum; +import lombok.extern.slf4j.Slf4j; +import com.example.exception.BadRequestException; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import java.util.List; + +/** + * 获取当前登录的用户 + * + * 2019-01-17 + */ +@Slf4j +public class SecurityUtils { + + /** + * 获取当前登录的用户 + * @return UserDetails + */ + public static UserDetails getCurrentUser() { + UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class); + return userDetailsService.loadUserByUsername(getCurrentUsername()); + } + + /** + * 获取系统用户名称 + * + * @return 系统用户名称 + */ + public static String getCurrentUsername() { + final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期"); + } + if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails userDetails = (UserDetails) authentication.getPrincipal(); + return userDetails.getUsername(); + } + throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息"); + } + + /** + * 获取系统用户ID + * @return 系统用户ID + */ + public static Long getCurrentUserId() { + UserDetails userDetails = getCurrentUser(); + return new JSONObject(new JSONObject(userDetails).get("user")).get("id", Long.class); + } + + /** + * 获取当前用户的数据权限 + * @return / + */ + public static List<Long> getCurrentUserDataScope(){ + UserDetails userDetails = getCurrentUser(); + JSONArray array = JSONUtil.parseArray(new JSONObject(userDetails).get("dataScopes")); + return JSONUtil.toList(array,Long.class); + } + + /** + * 获取数据权限级别 + * @return 级别 + */ + public static String getDataScopeType() { + List<Long> dataScopes = getCurrentUserDataScope(); + if(dataScopes.size() != 0){ + return ""; + } + return DataScopeEnum.ALL.getValue(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SpringContextHolder.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SpringContextHolder.java new file mode 100644 index 0000000..454b7c8 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/SpringContextHolder.java @@ -0,0 +1,145 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.env.Environment; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Jie + * 2019-01-07 + */ +@Slf4j +public class SpringContextHolder implements ApplicationContextAware, DisposableBean { + + private static ApplicationContext applicationContext = null; + private static final List<CallBack> CALL_BACKS = new ArrayList<>(); + private static boolean addCallback = true; + + /** + * 针对 某些初始化方法,在SpringContextHolder 未初始化时 提交回调方法。 + * 在SpringContextHolder 初始化后,进行回调使用 + * + * @param callBack 回调函数 + */ + public synchronized static void addCallBacks(CallBack callBack) { + if (addCallback) { + SpringContextHolder.CALL_BACKS.add(callBack); + } else { + log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName()); + callBack.executor(); + } + } + + /** + * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. + */ + @SuppressWarnings("unchecked") + public static <T> T getBean(String name) { + assertContextInjected(); + return (T) applicationContext.getBean(name); + } + + /** + * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. + */ + public static <T> T getBean(Class<T> requiredType) { + assertContextInjected(); + return applicationContext.getBean(requiredType); + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @param defaultValue 默认值 + * @param requiredType 返回类型 + * @return / + */ + public static <T> T getProperties(String property, T defaultValue, Class<T> requiredType) { + T result = defaultValue; + try { + result = getBean(Environment.class).getProperty(property, requiredType); + } catch (Exception ignored) {} + return result; + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @return / + */ + public static String getProperties(String property) { + return getProperties(property, null, String.class); + } + + /** + * 获取SpringBoot 配置信息 + * + * @param property 属性key + * @param requiredType 返回类型 + * @return / + */ + public static <T> T getProperties(String property, Class<T> requiredType) { + return getProperties(property, null, requiredType); + } + + /** + * 检查ApplicationContext不为空. + */ + private static void assertContextInjected() { + if (applicationContext == null) { + throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" + + ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder."); + } + } + + /** + * 清除SpringContextHolder中的ApplicationContext为Null. + */ + private static void clearHolder() { + log.debug("清除SpringContextHolder中的ApplicationContext:" + + applicationContext); + applicationContext = null; + } + + @Override + public void destroy() { + SpringContextHolder.clearHolder(); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if (SpringContextHolder.applicationContext != null) { + log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext); + } + SpringContextHolder.applicationContext = applicationContext; + if (addCallback) { + for (CallBack callBack : SpringContextHolder.CALL_BACKS) { + callBack.executor(); + } + CALL_BACKS.clear(); + } + SpringContextHolder.addCallback = false; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/StringUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/StringUtils.java new file mode 100644 index 0000000..a5fd454 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/StringUtils.java @@ -0,0 +1,264 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import com.example.config.ElAdminProperties; +import net.dreamlu.mica.ip2region.core.Ip2regionSearcher; +import net.dreamlu.mica.ip2region.core.IpInfo; +import nl.basjes.parse.useragent.UserAgent; +import nl.basjes.parse.useragent.UserAgentAnalyzer; +import javax.servlet.http.HttpServletRequest; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.util.Calendar; +import java.util.Date; +import java.util.Enumeration; + +/** + * + * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类 + */ +@Slf4j +public class StringUtils extends org.apache.commons.lang3.StringUtils { + + private static final char SEPARATOR = '_'; + private static final String UNKNOWN = "unknown"; + + /** + * 注入bean + */ + private final static Ip2regionSearcher IP_SEARCHER = SpringContextHolder.getBean(Ip2regionSearcher.class); + + + private static final UserAgentAnalyzer USER_AGENT_ANALYZER = UserAgentAnalyzer + .newBuilder() + .hideMatcherLoadStats() + .withCache(10000) + .withField(UserAgent.AGENT_NAME_VERSION) + .build(); + + /** + * 驼峰命名法工具 + * + * @return toCamelCase(" hello_world ") == "helloWorld" + * toCapitalizeCamelCase("hello_world") == "HelloWorld" + * toUnderScoreCase("helloWorld") = "hello_world" + */ + public static String toCamelCase(String s) { + if (s == null) { + return null; + } + + s = s.toLowerCase(); + + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == SEPARATOR) { + upperCase = true; + } else if (upperCase) { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } else { + sb.append(c); + } + } + + return sb.toString(); + } + + /** + * 驼峰命名法工具 + * + * @return toCamelCase(" hello_world ") == "helloWorld" + * toCapitalizeCamelCase("hello_world") == "HelloWorld" + * toUnderScoreCase("helloWorld") = "hello_world" + */ + public static String toCapitalizeCamelCase(String s) { + if (s == null) { + return null; + } + s = toCamelCase(s); + return s.substring(0, 1).toUpperCase() + s.substring(1); + } + + /** + * 驼峰命名法工具 + * + * @return toCamelCase(" hello_world ") == "helloWorld" + * toCapitalizeCamelCase("hello_world") == "HelloWorld" + * toUnderScoreCase("helloWorld") = "hello_world" + */ + static String toUnderScoreCase(String s) { + if (s == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + boolean nextUpperCase = true; + + if (i < (s.length() - 1)) { + nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); + } + + if ((i > 0) && Character.isUpperCase(c)) { + if (!upperCase || !nextUpperCase) { + sb.append(SEPARATOR); + } + upperCase = true; + } else { + upperCase = false; + } + + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 获取ip地址 + */ + public static String getIp(HttpServletRequest request) { + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + String comma = ","; + String localhost = "127.0.0.1"; + if (ip.contains(comma)) { + ip = ip.split(",")[0]; + } + if (localhost.equals(ip)) { + // 获取本机真正的ip地址 + try { + ip = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + log.error(e.getMessage(), e); + } + } + return ip; + } + + /** + * 根据ip获取详细地址 + */ + public static String getCityInfo(String ip) { + if (ElAdminProperties.ipLocal) { + return getLocalCityInfo(ip); + } else { + return getHttpCityInfo(ip); + } + } + + /** + * 根据ip获取详细地址 + */ + public static String getHttpCityInfo(String ip) { + String api = String.format(ElAdminConstant.Url.IP_URL, ip); + JSONObject object = JSONUtil.parseObj(HttpUtil.get(api)); + return object.get("addr", String.class); + } + + /** + * 根据ip获取详细地址 + */ + public static String getLocalCityInfo(String ip) { + IpInfo ipInfo = IP_SEARCHER.memorySearch(ip); + if(ipInfo != null){ + return ipInfo.getAddress(); + } + return null; + + } + + public static String getBrowser(HttpServletRequest request) { + UserAgent.ImmutableUserAgent userAgent = USER_AGENT_ANALYZER.parse(request.getHeader("User-Agent")); + return userAgent.get(UserAgent.AGENT_NAME_VERSION).getValue(); + } + + /** + * 获得当天是周几 + */ + public static String getWeekDay() { + String[] weekDays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + + int w = cal.get(Calendar.DAY_OF_WEEK) - 1; + if (w < 0) { + w = 0; + } + return weekDays[w]; + } + + /** + * 获取当前机器的IP + * + * @return / + */ + public static String getLocalIp() { + try { + InetAddress candidateAddress = null; + // 遍历所有的网络接口 + for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) { + NetworkInterface anInterface = interfaces.nextElement(); + // 在所有的接口下再遍历IP + for (Enumeration<InetAddress> inetAddresses = anInterface.getInetAddresses(); inetAddresses.hasMoreElements();) { + InetAddress inetAddr = inetAddresses.nextElement(); + // 排除loopback类型地址 + if (!inetAddr.isLoopbackAddress()) { + if (inetAddr.isSiteLocalAddress()) { + // 如果是site-local地址,就是它了 + return inetAddr.getHostAddress(); + } else if (candidateAddress == null) { + // site-local类型的地址未被发现,先记录候选地址 + candidateAddress = inetAddr; + } + } + } + } + if (candidateAddress != null) { + return candidateAddress.getHostAddress(); + } + // 如果没有发现 non-loopback地址.只能用最次选的方案 + InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); + if (jdkSuppliedAddress == null) { + return ""; + } + return jdkSuppliedAddress.getHostAddress(); + } catch (Exception e) { + return ""; + } + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ThrowableUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ThrowableUtil.java new file mode 100644 index 0000000..0ea7da7 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ThrowableUtil.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * 异常工具 2019-01-06 + * + */ +public class ThrowableUtil { + + /** + * 获取堆栈信息 + */ + public static String getStackTrace(Throwable throwable){ + StringWriter sw = new StringWriter(); + try (PrintWriter pw = new PrintWriter(sw)) { + throwable.printStackTrace(pw); + return sw.toString(); + } + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/TranslatorUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/TranslatorUtil.java new file mode 100644 index 0000000..7d7087d --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/TranslatorUtil.java @@ -0,0 +1,66 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import cn.hutool.json.JSONArray; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; + +/** + * + * 翻译工具类 + */ +public class TranslatorUtil { + + public static String translate(String word){ + try { + String url = "https://translate.googleapis.com/translate_a/single?" + + "client=gtx&" + + "sl=en" + + "&tl=zh-CN" + + "&dt=t&q=" + URLEncoder.encode(word, "UTF-8"); + + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + con.setRequestProperty("User-Agent", "Mozilla/5.0"); + + BufferedReader in = new BufferedReader( + new InputStreamReader(con.getInputStream())); + String inputLine; + StringBuilder response = new StringBuilder(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + return parseResult(response.toString()); + }catch (Exception e){ + return word; + } + } + + private static String parseResult(String inputJson){ + JSONArray jsonArray2 = (JSONArray) new JSONArray(inputJson).get(0); + StringBuilder result = new StringBuilder(); + for (Object o : jsonArray2) { + result.append(((JSONArray) o).get(0).toString()); + } + return result.toString(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ValidationUtil.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ValidationUtil.java new file mode 100644 index 0000000..689ec6f --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/ValidationUtil.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils; + +import cn.hutool.core.util.ObjectUtil; +import com.example.exception.BadRequestException; +import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; + +/** + * 验证工具 + * + * 2018-11-23 + */ +public class ValidationUtil{ + + /** + * 验证空 + */ + public static void isNull(Object obj, String entity, String parameter , Object value){ + if(ObjectUtil.isNull(obj)){ + String msg = entity + " 不存在: "+ parameter +" is "+ value; + throw new BadRequestException(msg); + } + } + + /** + * 验证是否为邮箱 + */ + public static boolean isEmail(String email) { + return new EmailValidator().isValid(email, null); + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeBiEnum.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeBiEnum.java new file mode 100644 index 0000000..4f0147e --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeBiEnum.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * <p> + * 验证码业务场景 + * </p> + * + * 2020-05-02 + */ +@Getter +@AllArgsConstructor +public enum CodeBiEnum { + + /* 旧邮箱修改邮箱 */ + ONE(1, "旧邮箱修改邮箱"), + + /* 通过邮箱修改密码 */ + TWO(2, "通过邮箱修改密码"); + + private final Integer code; + private final String description; + + public static CodeBiEnum find(Integer code) { + for (CodeBiEnum value : CodeBiEnum.values()) { + if (value.getCode().equals(code)) { + return value; + } + } + return null; + } + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeEnum.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeEnum.java new file mode 100644 index 0000000..17a1b2d --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/CodeEnum.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * <p> + * 验证码业务场景对应的 Redis 中的 key + * </p> + * + * 2020-05-02 + */ +@Getter +@AllArgsConstructor +public enum CodeEnum { + + /* 通过手机号码重置邮箱 */ + PHONE_RESET_EMAIL_CODE("phone_reset_email_code_", "通过手机号码重置邮箱"), + + /* 通过旧邮箱重置邮箱 */ + EMAIL_RESET_EMAIL_CODE("email_reset_email_code_", "通过旧邮箱重置邮箱"), + + /* 通过手机号码重置密码 */ + PHONE_RESET_PWD_CODE("phone_reset_pwd_code_", "通过手机号码重置密码"), + + /* 通过邮箱重置密码 */ + EMAIL_RESET_PWD_CODE("email_reset_pwd_code_", "通过邮箱重置密码"); + + private final String key; + private final String description; +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/DataScopeEnum.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/DataScopeEnum.java new file mode 100644 index 0000000..18330f2 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/DataScopeEnum.java @@ -0,0 +1,53 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * <p> + * 数据权限枚举 + * </p> + * + * 2020-05-07 + */ +@Getter +@AllArgsConstructor +public enum DataScopeEnum { + + /* 全部的数据权限 */ + ALL("全部", "全部的数据权限"), + + /* 自己部门的数据权限 */ + THIS_LEVEL("本级", "自己部门的数据权限"), + + /* 自定义的数据权限 */ + CUSTOMIZE("自定义", "自定义的数据权限"); + + private final String value; + private final String description; + + public static DataScopeEnum find(String val) { + for (DataScopeEnum dataScopeEnum : DataScopeEnum.values()) { + if (dataScopeEnum.getValue().equals(val)) { + return dataScopeEnum; + } + } + return null; + } + +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/RequestMethodEnum.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/RequestMethodEnum.java new file mode 100644 index 0000000..2edd703 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/enums/RequestMethodEnum.java @@ -0,0 +1,74 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.utils.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * + * @website https://el-admin.vip + * @description + * 2020-06-10 + **/ +@Getter +@AllArgsConstructor +public enum RequestMethodEnum { + + /** + * 搜寻 @AnonymousGetMapping + */ + GET("GET"), + + /** + * 搜寻 @AnonymousPostMapping + */ + POST("POST"), + + /** + * 搜寻 @AnonymousPutMapping + */ + PUT("PUT"), + + /** + * 搜寻 @AnonymousPatchMapping + */ + PATCH("PATCH"), + + /** + * 搜寻 @AnonymousDeleteMapping + */ + DELETE("DELETE"), + + /** + * 否则就是所有 Request 接口都放行 + */ + ALL("All"); + + /** + * Request 类型 + */ + private final String type; + + public static RequestMethodEnum find(String type) { + for (RequestMethodEnum value : RequestMethodEnum.values()) { + if (value.getType().equals(type)) { + return value; + } + } + return ALL; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/PageUtils.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/PageUtils.java new file mode 100644 index 0000000..7f02b02 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/PageUtils.java @@ -0,0 +1,145 @@ +/** + + * + + * + * + */ + +package com.example.utils.page; + + + +import com.baomidou.mybatisplus.core.metadata.IPage; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页工具类 + * + * @author Mark [email protected] + */ +public class PageUtils implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 总记录数 + */ + private int total; + /** + * 每页记录数 + */ + private int size; + /** + * 总页数 + */ + private int pages; + /** + * 当前页数 + */ + private int page; + /** + * 列表数据 + */ + private List<?> list; + + private double totalTime; + + private Object independentIpNum; + + private int resultTotal; + + public int getResultTotal() { + return resultTotal; + } + + public void setResultTotal(int resultTotal) { + this.resultTotal = resultTotal; + } + + /** + * 分页 + * @param list 列表数据 + * @param total 总记录数 + * @param size 每页记录数 + * @param page 当前页数 + */ + public PageUtils(List<?> list, int total, int size, int page ,double totalTime,int independentIpNum ,int resultTotal) { + this.list = list; + this.total = total; + this.size = size; + this.page = page; + this.totalTime = totalTime; + this.independentIpNum = independentIpNum; + this.resultTotal = resultTotal; + this.pages = (int)Math.ceil((double)total/size); + } + + /** + * 分页 + */ + public PageUtils(IPage<?> page) { + this.list = page.getRecords(); + this.total = (int)page.getTotal(); + this.size = (int)page.getSize(); + this.page = (int)page.getCurrent(); + this.pages = (int)page.getPages(); + } + + + public Object getIndependentIpNum() { + return independentIpNum; + } + + public void setIndependentIpNum(Object independentIpNum) { + this.independentIpNum = independentIpNum; + } + + public int getTotal() { + return total; + } + + public void setTotal(int total) { + this.total = total; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } + + public int getPages() { + return pages; + } + + public void setPages(int pages) { + this.pages = pages; + } + + public int getPage() { + return page; + } + + public double getTotalTime() { + return totalTime; + } + + public void setTotalTime(double totalTime) { + this.totalTime = totalTime; + } + + public void setPage(int page) { + this.page = page; + } + + public List<?> getList() { + return list; + } + + public void setList(List<?> list) { + this.list = list; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/Query.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/Query.java new file mode 100644 index 0000000..765f2f6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/Query.java @@ -0,0 +1,64 @@ +package com.example.utils.page; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import java.util.Map; + +/** + * 查询参数 + */ +public class Query { + + private Class clz; + + public Class<? extends Object> getClz() { + return clz; + } + + public void setClz(Class clz) { + this.clz = clz; + } + + public Query(Class clz) { + this.clz = clz; + } + + public IPage getPage(Map<String, Object> params) { + return this.getPage(params, null, false); + } + + public IPage getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) { + //分页参数 + long curPage = 1; + long limit = 10; + + if(params.get("page") != null && !"".equals(params.get("page"))){ + curPage = Long.parseLong((String)params.get("page")); + } + if(params.get("size") != null && !"".equals(params.get("size"))){ + limit = Long.parseLong((String)params.get("size")); + if(limit == -1){ + limit = Long.MAX_VALUE; + curPage = 0; + } + } + + //分页对象 + Page page = new Page(curPage, limit); + + //分页参数 + params.put("page", page); + + + // 默认排序 + if(isAsc) { + page.setAsc(defaultOrderField); + }else { + page.setDesc(defaultOrderField); + } + + return page; + } +} diff --git a/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/R.java b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/R.java new file mode 100644 index 0000000..92db65a --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-common/src/main/java/com/example/utils/page/R.java @@ -0,0 +1,40 @@ +package com.example.utils.page; + +import cn.hutool.core.date.DateUtil; + +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +public class R extends HashMap<String, Object> { + private static final long serialVersionUID = 1L; + + public R() { + put("status", 200); + put("message", "success"); + put("timestamp", new Date()); + } + + public static R ok(String message) { + R r = new R(); + r.put("message", message); + r.put("timestamp", new Date()); + return r; + } + + public static R ok() { + return new R(); + } + + public static R ok(Object data) { + R r = new R(); + r.put("data", data); + r.put("timestamp", new Date()); + return r; + } + + +} + + diff --git a/UI source code/dns-dev-2.0/dns-logging/pom.xml b/UI source code/dns-dev-2.0/dns-logging/pom.xml new file mode 100644 index 0000000..f3c2cc9 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/pom.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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"> + <parent> + <artifactId>dns</artifactId> + <groupId>com.example</groupId> + <version>2.6</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>dns-logging</artifactId> + <name>dns-logging</name> + + <dependencies> + <dependency> + <groupId>com.example</groupId> + <artifactId>dns-common</artifactId> + <version>2.6</version> + </dependency> + </dependencies> +</project> diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/annotation/Log.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/annotation/Log.java new file mode 100644 index 0000000..566b555 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/annotation/Log.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * 2018-11-24 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Log { + String value() default ""; +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/aspect/LogAspect.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/aspect/LogAspect.java new file mode 100644 index 0000000..aaed973 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/aspect/LogAspect.java @@ -0,0 +1,98 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.aspect; + +import com.example.utils.RequestHolder; +import com.example.utils.SecurityUtils; +import com.example.utils.StringUtils; +import com.example.utils.ThrowableUtil; +import lombok.extern.slf4j.Slf4j; +import com.example.domain.Log; +import com.example.service.LogService; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; + +/** + * + * 2018-11-24 + */ +@Component +@Aspect +@Slf4j +public class LogAspect { + + private final LogService logService; + + ThreadLocal<Long> currentTime = new ThreadLocal<>(); + + public LogAspect(LogService logService) { + this.logService = logService; + } + + /** + * 配置切入点 + */ + @Pointcut("@annotation(com.example.annotation.Log)") + public void logPointcut() { + // 该方法无方法体,主要为了让同类中其他方法使用此切入点 + } + + /** + * 配置环绕通知,使用在方法logPointcut()上注册的切入点 + * + * @param joinPoint join point for advice + */ + @Around("logPointcut()") + public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { + Object result; + currentTime.set(System.currentTimeMillis()); + result = joinPoint.proceed(); + Log log = new Log("INFO",System.currentTimeMillis() - currentTime.get()); + currentTime.remove(); + HttpServletRequest request = RequestHolder.getHttpServletRequest(); + logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request),joinPoint, log); + return result; + } + + /** + * 配置异常通知 + * + * @param joinPoint join point for advice + * @param e exception + */ + @AfterThrowing(pointcut = "logPointcut()", throwing = "e") + public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { + Log log = new Log("ERROR",System.currentTimeMillis() - currentTime.get()); + currentTime.remove(); + log.setExceptionDetail(ThrowableUtil.getStackTrace(e).getBytes()); + HttpServletRequest request = RequestHolder.getHttpServletRequest(); + logService.save(getUsername(), StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint)joinPoint, log); + } + + public String getUsername() { + try { + return SecurityUtils.getCurrentUsername(); + }catch (Exception e){ + return ""; + } + } +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/domain/Log.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/domain/Log.java new file mode 100644 index 0000000..21529a6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/domain/Log.java @@ -0,0 +1,80 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.domain; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.CreationTimestamp; +import javax.persistence.*; +import java.io.Serializable; +import java.sql.Timestamp; + +/** + * + * 2018-11-24 + */ +@Entity +@Getter +@Setter +@Table(name = "sys_log") +@NoArgsConstructor +public class Log implements Serializable { + + @Id + @Column(name = "log_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** 操作用户 */ + private String username; + + /** 描述 */ + private String description; + + /** 方法名 */ + private String method; + + /** 参数 */ + private String params; + + /** 日志类型 */ + private String logType; + + /** 请求ip */ + private String requestIp; + + /** 地址 */ + private String address; + + /** 浏览器 */ + private String browser; + + /** 请求耗时 */ + private Long time; + + /** 异常详细 */ + private byte[] exceptionDetail; + + /** 创建日期 */ + @CreationTimestamp + private Timestamp createTime; + + public Log(String logType, Long time) { + this.logType = logType; + this.time = time; + } +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/repository/LogRepository.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/repository/LogRepository.java new file mode 100644 index 0000000..d689cfe --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/repository/LogRepository.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.repository; + +import com.example.domain.Log; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +/** + * + * 2018-11-24 + */ +@Repository +public interface LogRepository extends JpaRepository<Log,Long>, JpaSpecificationExecutor<Log> { + + /** + * 根据日志类型删除信息 + * @param logType 日志类型 + */ + @Modifying + @Query(value = "delete from sys_log where log_type = ?1", nativeQuery = true) + void deleteByLogType(String logType); +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/rest/LogController.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/rest/LogController.java new file mode 100644 index 0000000..305f2bb --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/rest/LogController.java @@ -0,0 +1,109 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.rest; + +import com.example.utils.SecurityUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import com.example.annotation.Log; +import com.example.service.LogService; +import com.example.service.dto.LogQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * + * 2018-11-24 + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/logs") +@Api(tags = "系统:日志管理") +public class LogController { + + private final LogService logService; + + @Log("导出数据") + @ApiOperation("导出数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check()") + public void exportLog(HttpServletResponse response, LogQueryCriteria criteria) throws IOException { + criteria.setLogType("INFO"); + logService.download(logService.queryAll(criteria), response); + } + + @Log("导出错误数据") + @ApiOperation("导出错误数据") + @GetMapping(value = "/error/download") + @PreAuthorize("@el.check()") + public void exportErrorLog(HttpServletResponse response, LogQueryCriteria criteria) throws IOException { + criteria.setLogType("ERROR"); + logService.download(logService.queryAll(criteria), response); + } + @GetMapping + @ApiOperation("日志查询") + @PreAuthorize("@el.check()") + public ResponseEntity<Object> queryLog(LogQueryCriteria criteria, Pageable pageable){ + criteria.setLogType("INFO"); + return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK); + } + + @GetMapping(value = "/user") + @ApiOperation("用户日志查询") + public ResponseEntity<Object> queryUserLog(LogQueryCriteria criteria, Pageable pageable){ + criteria.setLogType("INFO"); + criteria.setBlurry(SecurityUtils.getCurrentUsername()); + return new ResponseEntity<>(logService.queryAllByUser(criteria,pageable), HttpStatus.OK); + } + + @GetMapping(value = "/error") + @ApiOperation("错误日志查询") + @PreAuthorize("@el.check()") + public ResponseEntity<Object> queryErrorLog(LogQueryCriteria criteria, Pageable pageable){ + criteria.setLogType("ERROR"); + return new ResponseEntity<>(logService.queryAll(criteria,pageable), HttpStatus.OK); + } + + @GetMapping(value = "/error/{id}") + @ApiOperation("日志异常详情查询") + @PreAuthorize("@el.check()") + public ResponseEntity<Object> queryErrorLogDetail(@PathVariable Long id){ + return new ResponseEntity<>(logService.findByErrDetail(id), HttpStatus.OK); + } + @DeleteMapping(value = "/del/error") + @Log("删除所有ERROR日志") + @ApiOperation("删除所有ERROR日志") + @PreAuthorize("@el.check()") + public ResponseEntity<Object> delAllErrorLog(){ + logService.delAllByError(); + return new ResponseEntity<>(HttpStatus.OK); + } + + @DeleteMapping(value = "/del/info") + @Log("删除所有INFO日志") + @ApiOperation("删除所有INFO日志") + @PreAuthorize("@el.check()") + public ResponseEntity<Object> delAllInfoLog(){ + logService.delAllByInfo(); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/LogService.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/LogService.java new file mode 100644 index 0000000..b640559 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/LogService.java @@ -0,0 +1,92 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.service; + +import com.example.domain.Log; +import com.example.service.dto.LogQueryCriteria; +import org.aspectj.lang.ProceedingJoinPoint; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Async; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +/** + * + * 2018-11-24 + */ +public interface LogService { + + /** + * 分页查询 + * @param criteria 查询条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(LogQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria 查询条件 + * @return / + */ + List<Log> queryAll(LogQueryCriteria criteria); + + /** + * 查询用户日志 + * @param criteria 查询条件 + * @param pageable 分页参数 + * @return - + */ + Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable); + + /** + * 保存日志数据 + * @param username 用户 + * @param browser 浏览器 + * @param ip 请求IP + * @param joinPoint / + * @param log 日志实体 + */ + @Async + void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log); + + /** + * 查询异常详情 + * @param id 日志ID + * @return Object + */ + Object findByErrDetail(Long id); + + /** + * 导出日志 + * @param logs 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List<Log> logs, HttpServletResponse response) throws IOException; + + /** + * 删除所有错误日志 + */ + void delAllByError(); + + /** + * 删除所有INFO日志 + */ + void delAllByInfo(); +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogErrorDTO.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogErrorDTO.java new file mode 100644 index 0000000..734bda3 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogErrorDTO.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.service.dto; + +import lombok.Data; +import java.io.Serializable; +import java.sql.Timestamp; + +/** +* +* 2019-5-22 +*/ +@Data +public class LogErrorDTO implements Serializable { + + private Long id; + + private String username; + + private String description; + + private String method; + + private String params; + + private String browser; + + private String requestIp; + + private String address; + + private Timestamp createTime; +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogQueryCriteria.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogQueryCriteria.java new file mode 100644 index 0000000..9611dfb --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogQueryCriteria.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.service.dto; + +import lombok.Data; +import com.example.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** + * 日志查询类 + * + * 2019-6-4 09:23:07 + */ +@Data +public class LogQueryCriteria { + + @Query(blurry = "username,description,address,requestIp,method,params") + private String blurry; + + @Query + private String logType; + + @Query(type = Query.Type.BETWEEN) + private List<Timestamp> createTime; +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogSmallDTO.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogSmallDTO.java new file mode 100644 index 0000000..d78f9d9 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/dto/LogSmallDTO.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.service.dto; + +import lombok.Data; +import java.io.Serializable; +import java.sql.Timestamp; + +/** + * + * 2019-5-22 + */ +@Data +public class LogSmallDTO implements Serializable { + + private String description; + + private String requestIp; + + private Long time; + + private String address; + + private String browser; + + private Timestamp createTime; +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/impl/LogServiceImpl.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/impl/LogServiceImpl.java new file mode 100644 index 0000000..43b94b8 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/impl/LogServiceImpl.java @@ -0,0 +1,169 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.service.impl; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import com.example.domain.Log; +import com.example.service.LogService; +import com.example.service.dto.LogQueryCriteria; +import com.example.utils.*; +import lombok.RequiredArgsConstructor; +import com.example.repository.LogRepository; +import com.example.service.mapstruct.LogErrorMapper; +import com.example.service.mapstruct.LogSmallMapper; +import com.example.utils.*; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.*; + +/** + * + * 2018-11-24 + */ +@Service +@RequiredArgsConstructor +public class LogServiceImpl implements LogService { + private final LogRepository logRepository; + private final LogErrorMapper logErrorMapper; + private final LogSmallMapper logSmallMapper; + + @Override + public Object queryAll(LogQueryCriteria criteria, Pageable pageable) { + Page<Log> page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)), pageable); + String status = "ERROR"; + if (status.equals(criteria.getLogType())) { + return PageUtil.toPage(page.map(logErrorMapper::toDto)); + } + return page; + } + + @Override + public List<Log> queryAll(LogQueryCriteria criteria) { + return logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb))); + } + + @Override + public Object queryAllByUser(LogQueryCriteria criteria, Pageable pageable) { + Page<Log> page = logRepository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)), pageable); + return PageUtil.toPage(page.map(logSmallMapper::toDto)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void save(String username, String browser, String ip, ProceedingJoinPoint joinPoint, Log log) { + if (log == null) { + throw new IllegalArgumentException("Log 不能为 null!"); + } + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + com.example.annotation.Log aopLog = method.getAnnotation(com.example.annotation.Log.class); + + // 方法路径 + String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()"; + + // 描述 + log.setDescription(aopLog.value()); + + log.setRequestIp(ip); + log.setAddress(StringUtils.getCityInfo(log.getRequestIp())); + log.setMethod(methodName); + log.setUsername(username); + log.setParams(getParameter(method, joinPoint.getArgs())); + log.setBrowser(browser); + logRepository.save(log); + } + + /** + * 根据方法和传入的参数获取请求参数 + */ + private String getParameter(Method method, Object[] args) { + List<Object> argList = new ArrayList<>(); + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < parameters.length; i++) { + //将RequestBody注解修饰的参数作为请求参数 + RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class); + if (requestBody != null) { + argList.add(args[i]); + } + //将RequestParam注解修饰的参数作为请求参数 + RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class); + if (requestParam != null) { + Map<String, Object> map = new HashMap<>(4); + String key = parameters[i].getName(); + if (!StringUtils.isEmpty(requestParam.value())) { + key = requestParam.value(); + } + map.put(key, args[i]); + argList.add(map); + } + } + if (argList.isEmpty()) { + return ""; + } + return argList.size() == 1 ? JSONUtil.toJsonStr(argList.get(0)) : JSONUtil.toJsonStr(argList); + } + + @Override + public Object findByErrDetail(Long id) { + Log log = logRepository.findById(id).orElseGet(Log::new); + ValidationUtil.isNull(log.getId(), "Log", "id", id); + byte[] details = log.getExceptionDetail(); + return Dict.create().set("exception", new String(ObjectUtil.isNotNull(details) ? details : "".getBytes())); + } + + @Override + public void download(List<Log> logs, HttpServletResponse response) throws IOException { + List<Map<String, Object>> list = new ArrayList<>(); + for (Log log : logs) { + Map<String, Object> map = new LinkedHashMap<>(); + map.put("用户名", log.getUsername()); + map.put("IP", log.getRequestIp()); + map.put("IP来源", log.getAddress()); + map.put("描述", log.getDescription()); + map.put("浏览器", log.getBrowser()); + map.put("请求耗时/毫秒", log.getTime()); + map.put("异常详情", new String(ObjectUtil.isNotNull(log.getExceptionDetail()) ? log.getExceptionDetail() : "".getBytes())); + map.put("创建日期", log.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delAllByError() { + logRepository.deleteByLogType("ERROR"); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delAllByInfo() { + logRepository.deleteByLogType("INFO"); + } +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogErrorMapper.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogErrorMapper.java new file mode 100644 index 0000000..8a19a28 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogErrorMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.service.mapstruct; + +import com.example.base.BaseMapper; +import com.example.domain.Log; +import com.example.service.dto.LogErrorDTO; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * + * 2019-5-22 + */ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface LogErrorMapper extends BaseMapper<LogErrorDTO, Log> { + +} diff --git a/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogSmallMapper.java b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogSmallMapper.java new file mode 100644 index 0000000..8c06ba4 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-logging/src/main/java/com/example/service/mapstruct/LogSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.service.mapstruct; + +import com.example.base.BaseMapper; +import com.example.domain.Log; +import com.example.service.dto.LogSmallDTO; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * + * 2019-5-22 + */ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface LogSmallMapper extends BaseMapper<LogSmallDTO, Log> { + +} diff --git a/UI source code/dns-dev-2.0/dns-system/pom.xml b/UI source code/dns-dev-2.0/dns-system/pom.xml new file mode 100644 index 0000000..ea50602 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/pom.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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"> + <parent> + <artifactId>dns</artifactId> + <groupId>com.example</groupId> + <version>2.6</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>dns-system</artifactId> + <name>dns-system</name> + + <properties> + <jjwt.version>0.11.1</jjwt.version> + <!-- oshi监控需要指定jna版本, 问题详见 https://github.com/oshi/oshi/issues/1040 --> + <jna.version>5.8.0</jna.version> + + </properties> + + <dependencies> + + <!-- tools 模块包含了 common 和 logging 模块 --> + <dependency> + <groupId>com.example</groupId> + <artifactId>dns-common</artifactId> + <version>2.6</version> + </dependency> + <dependency> + <groupId>com.example</groupId> + <artifactId>dns-logging</artifactId> + <version>2.6</version> + </dependency> + + <!-- Spring boot websocket --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-websocket</artifactId> + </dependency> + + + <!-- jwt --> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-api</artifactId> + <version>${jjwt.version}</version> + </dependency> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-impl</artifactId> + <version>${jjwt.version}</version> + </dependency> + <dependency> + <groupId>io.jsonwebtoken</groupId> + <artifactId>jjwt-jackson</artifactId> + <version>${jjwt.version}</version> + </dependency> + + <!-- quartz --> + <dependency> + <groupId>org.quartz-scheduler</groupId> + <artifactId>quartz</artifactId> + </dependency> + + <!-- linux的管理 --> + <dependency> + <groupId>ch.ethz.ganymed</groupId> + <artifactId>ganymed-ssh2</artifactId> + <version>build210</version> + </dependency> + <dependency> + <groupId>com.jcraft</groupId> + <artifactId>jsch</artifactId> + <version>0.1.55</version> + </dependency> + + <!-- 获取系统信息 --> + <dependency> + <groupId>com.github.oshi</groupId> + <artifactId>oshi-core</artifactId> + <version>5.7.1</version> + </dependency> + </dependencies> + + <!-- 打包 --> + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + </plugin> + <!-- 跳过单元测试 --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <skipTests>true</skipTests> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/AppRun.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/AppRun.java new file mode 100644 index 0000000..521f939 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/AppRun.java @@ -0,0 +1,64 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example; + +import com.example.utils.SpringContextHolder; +import io.swagger.annotations.Api; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.ApplicationPidFileWriter; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.servlet.server.ServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.bind.annotation.RestController; + +/** + * 开启审计功能 -> @EnableJpaAuditing + * + * 2018/11/15 9:20:19 + */ +@EnableAsync +@RestController +@Api(hidden = true) +@SpringBootApplication +@EnableTransactionManagement +@EnableJpaAuditing(auditorAwareRef = "auditorAware") +public class AppRun { + + public static void main(String[] args) { + SpringApplication springApplication = new SpringApplication(AppRun.class); + // 监控应用的PID,启动时可指定PID路径:--spring.pid.file=/home/dns/app.pid + // 或者在 application.yml 添加文件路径,方便 kill,kill `cat /home/dns/app.pid` + springApplication.addListeners(new ApplicationPidFileWriter()); + springApplication.run(args); + } + + @Bean + public SpringContextHolder springContextHolder() { + return new SpringContextHolder(); + } + + @Bean + public ServletWebServerFactory webServerFactory() { + TomcatServletWebServerFactory fa = new TomcatServletWebServerFactory(); + fa.addConnectorCustomizers(connector -> connector.setProperty("relaxedQueryChars", "[]{}")); + return fa; + } + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/ConfigurerAdapter.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/ConfigurerAdapter.java new file mode 100644 index 0000000..b2bcf86 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/ConfigurerAdapter.java @@ -0,0 +1,88 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config; + +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * WebMvcConfigurer + * + * + * 2018-11-30 + */ +@Configuration +@EnableWebMvc +public class ConfigurerAdapter implements WebMvcConfigurer { + + /** 文件配置 */ + private final FileProperties properties; + + public ConfigurerAdapter(FileProperties properties) { + this.properties = properties; + } + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOrigin("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + FileProperties.ElPath path = properties.getPath(); + String avatarUtl = "file:" + path.getAvatar().replace("\\","/"); + String pathUtl = "file:" + path.getPath().replace("\\","/"); + registry.addResourceHandler("/avatar/**").addResourceLocations(avatarUtl).setCachePeriod(0); + registry.addResourceHandler("/file/**").addResourceLocations(pathUtl).setCachePeriod(0); + registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0); + } + + @Override + public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { + // 使用 fastjson 序列化,会导致 @JsonIgnore 失效,可以使用 @JSONField(serialize = false) 替换 + FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); + List<MediaType> supportMediaTypeList = new ArrayList<>(); + supportMediaTypeList.add(MediaType.APPLICATION_JSON); + FastJsonConfig config = new FastJsonConfig(); + config.setDateFormat("yyyy-MM-dd HH:mm:ss"); + config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect); + converter.setFastJsonConfig(config); + converter.setSupportedMediaTypes(supportMediaTypeList); + converter.setDefaultCharset(StandardCharsets.UTF_8); + converters.add(converter); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusConfig.java new file mode 100644 index 0000000..87e8cbf --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusConfig.java @@ -0,0 +1,236 @@ +package com.example.config; + +import cn.hutool.log.Log; +import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties; +import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS; +import com.baomidou.mybatisplus.core.MybatisConfiguration; +import com.baomidou.mybatisplus.core.config.GlobalConfig; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; +import com.baomidou.mybatisplus.core.injector.ISqlInjector; +import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.mapping.DatabaseIdProvider; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.mapper.ClassPathMapperScanner; +import org.mybatis.spring.mapper.MapperFactoryBean; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.context.annotation.*; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import javax.sql.DataSource; +import java.util.List; + +/** + * mybatis-plus 初始化配置 + */ +@Configuration +@EnableConfigurationProperties(MybatisPlusProperties.class) +public class MybatisPlusConfig { + + public MybatisPlusConfig(MybatisPlusProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, + ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, + ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider, + ApplicationContext applicationContext) { + this.properties = properties; + this.interceptors = interceptorsProvider.getIfAvailable(); + this.resourceLoader = resourceLoader; + this.databaseIdProvider = databaseIdProvider.getIfAvailable(); + this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable(); + this.applicationContext = applicationContext; + } + + private static final Log logger = Log.get(); + + private final MybatisPlusProperties properties; + + private final Interceptor[] interceptors; + + private final ResourceLoader resourceLoader; + + private final DatabaseIdProvider databaseIdProvider; + + private final List<ConfigurationCustomizer> configurationCustomizers; + + private final ApplicationContext applicationContext; + + @PostConstruct + public void checkConfigFileExists() { + if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) { + Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation()); + Assert.state(resource.exists(), "Cannot find config location: " + resource + + " (please add config file or check your Mybatis configuration)"); + } + } + + @Bean + @ConditionalOnMissingBean + public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { + MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); + factory.setDataSource(dataSource); + factory.setVfs(SpringBootVFS.class); + if (StringUtils.hasText(this.properties.getConfigLocation())) { + factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); + } + applyConfiguration(factory); + if (this.properties.getConfigurationProperties() != null) { + factory.setConfigurationProperties(this.properties.getConfigurationProperties()); + } + if (!ObjectUtils.isEmpty(this.interceptors)) { + factory.setPlugins(this.interceptors); + } + if (this.databaseIdProvider != null) { + factory.setDatabaseIdProvider(this.databaseIdProvider); + } + if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { + factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); + } + // TODO 自定义枚举包 + if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) { + factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage()); + } + if (this.properties.getTypeAliasesSuperType() != null) { + factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType()); + } + if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { + factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); + } + if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { + factory.setMapperLocations(this.properties.resolveMapperLocations()); + } + // TODO 此处必为非 NULL + GlobalConfig globalConfig = this.properties.getGlobalConfig(); + // 注入填充器 + if (this.applicationContext.getBeanNamesForType(MetaObjectHandler.class, false, false).length > 0) { + MetaObjectHandler metaObjectHandler = this.applicationContext.getBean(MetaObjectHandler.class); + globalConfig.setMetaObjectHandler(metaObjectHandler); + } + // 注入主键生成器 + if (this.applicationContext.getBeanNamesForType(IKeyGenerator.class, false, false).length > 0) { + IKeyGenerator keyGenerator = this.applicationContext.getBean(IKeyGenerator.class); + globalConfig.getDbConfig().setKeyGenerator(keyGenerator); + } + // 注入sql注入器 + if (this.applicationContext.getBeanNamesForType(ISqlInjector.class, false, false).length > 0) { + ISqlInjector iSqlInjector = this.applicationContext.getBean(ISqlInjector.class); + globalConfig.setSqlInjector(iSqlInjector); + } + factory.setGlobalConfig(globalConfig); + return factory.getObject(); + } + + private void applyConfiguration(MybatisSqlSessionFactoryBean factory) { + MybatisConfiguration configuration = this.properties.getConfiguration(); + if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { + configuration = new MybatisConfiguration(); + } + if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { + for (ConfigurationCustomizer customizer : this.configurationCustomizers) { + customizer.customize(configuration); + } + } + factory.setConfiguration(configuration); + } + + @Bean + @ConditionalOnMissingBean + public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { + ExecutorType executorType = this.properties.getExecutorType(); + if (executorType != null) { + return new SqlSessionTemplate(sqlSessionFactory, executorType); + } else { + return new SqlSessionTemplate(sqlSessionFactory); + } + } + + /** + * This will just scan the same base package as Spring Boot does. If you want + * more power, you can explicitly use + * {@link org.mybatis.spring.annotation.MapperScan} but this will get typed + * mappers working correctly, out-of-the-box, similar to using Spring Data JPA + * repositories. + */ + public static class AutoConfiguredMapperScannerRegistrar + implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware { + + private BeanFactory beanFactory; + + private ResourceLoader resourceLoader; + + @Override + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, + BeanDefinitionRegistry registry) { + + logger.debug("Searching for mappers annotated with @Mapper"); + + ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); + + try { + if (this.resourceLoader != null) { + scanner.setResourceLoader(this.resourceLoader); + } + + List<String> packages = AutoConfigurationPackages.get(this.beanFactory); + if (logger.isDebugEnabled()) { + packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg)); + } + + scanner.setAnnotationClass(Mapper.class); + scanner.registerFilters(); + scanner.doScan(StringUtils.toStringArray(packages)); + } catch (IllegalStateException ex) { + logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex); + } + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + } + + /** + * {@link org.mybatis.spring.annotation.MapperScan} ultimately ends up creating + * instances of {@link MapperFactoryBean}. If + * {@link org.mybatis.spring.annotation.MapperScan} is used then this + * auto-configuration is not needed. If it is _not_ used, however, then this + * will bring in a bean registrar and automatically register components based on + * the same component-scanning path as Spring Boot itself. + */ + @Configuration + @Import({ AutoConfiguredMapperScannerRegistrar.class }) + @ConditionalOnMissingBean(MapperFactoryBean.class) + public static class MapperScannerRegistrarNotFoundConfiguration { + + @PostConstruct + public void afterPropertiesSet() { + logger.debug("No {} found.", MapperFactoryBean.class.getName()); + } + } + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusPluginsConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusPluginsConfig.java new file mode 100644 index 0000000..cc9739c --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/MybatisPlusPluginsConfig.java @@ -0,0 +1,36 @@ +package com.example.config; + +import cn.hutool.log.Log; +import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; +import com.baomidou.mybatisplus.core.injector.ISqlInjector; +import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector; +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +/** + * mybatis-plus 插件配置 + */ +@Configuration +public class MybatisPlusPluginsConfig { + + private static final Log logger = Log.get(); + + /** + * 分页插件 + */ + @Bean + public PaginationInterceptor paginationInterceptor() { + return new PaginationInterceptor(); + } + + + @Bean + public ISqlInjector sqlInjector() { + return new LogicSqlInjector(); + } + + + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/WebSocketConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/WebSocketConfig.java new file mode 100644 index 0000000..906021c --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/WebSocketConfig.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/** + * @author ZhangHouYing + * 2019-08-24 15:44 + */ +@Configuration +public class WebSocketConfig { + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskExecutePool.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskExecutePool.java new file mode 100644 index 0000000..44abd3d --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskExecutePool.java @@ -0,0 +1,62 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config.thread; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 异步任务线程池装配类 + * @author https://juejin.im/entry/5abb8f6951882555677e9da2 + * 2019年10月31日15:06:18 + */ +@Slf4j +@Configuration +public class AsyncTaskExecutePool implements AsyncConfigurer { + + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + //核心线程池大小 + executor.setCorePoolSize(AsyncTaskProperties.corePoolSize); + //最大线程数 + executor.setMaxPoolSize(AsyncTaskProperties.maxPoolSize); + //队列容量 + executor.setQueueCapacity(AsyncTaskProperties.queueCapacity); + //活跃时间 + executor.setKeepAliveSeconds(AsyncTaskProperties.keepAliveSeconds); + //线程名字前缀 + executor.setThreadNamePrefix("el-async-"); + // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 + // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); + return executor; + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return (throwable, method, objects) -> { + log.error("===="+throwable.getMessage()+"====", throwable); + log.error("exception method:"+method.getName()); + }; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskProperties.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskProperties.java new file mode 100644 index 0000000..012a127 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/AsyncTaskProperties.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config.thread; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * 线程池配置属性类 + * @author https://juejin.im/entry/5abb8f6951882555677e9da2 + * 2019年10月31日14:58:18 + */ +@Data +@Component +public class AsyncTaskProperties { + + public static int corePoolSize; + + public static int maxPoolSize; + + public static int keepAliveSeconds; + + public static int queueCapacity; + + @Value("${task.pool.core-pool-size}") + public void setCorePoolSize(int corePoolSize) { + AsyncTaskProperties.corePoolSize = corePoolSize; + } + + @Value("${task.pool.max-pool-size}") + public void setMaxPoolSize(int maxPoolSize) { + AsyncTaskProperties.maxPoolSize = maxPoolSize; + } + + @Value("${task.pool.keep-alive-seconds}") + public void setKeepAliveSeconds(int keepAliveSeconds) { + AsyncTaskProperties.keepAliveSeconds = keepAliveSeconds; + } + + @Value("${task.pool.queue-capacity}") + public void setQueueCapacity(int queueCapacity) { + AsyncTaskProperties.queueCapacity = queueCapacity; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/TheadFactoryName.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/TheadFactoryName.java new file mode 100644 index 0000000..b06a723 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/TheadFactoryName.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config.thread; + +import org.springframework.stereotype.Component; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 自定义线程名称 + * + * 2019年10月31日17:49:55 + */ +@Component +public class TheadFactoryName implements ThreadFactory { + + private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); + private final ThreadGroup group; + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final String namePrefix; + + public TheadFactoryName() { + this("el-pool"); + } + + private TheadFactoryName(String name){ + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + //此时namePrefix就是 name + 第几个用这个工厂创建线程池的 + this.namePrefix = name + + POOL_NUMBER.getAndIncrement(); + } + + @Override + public Thread newThread(Runnable r) { + //此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程 + Thread t = new Thread(group, r, + namePrefix + "-thread-"+threadNumber.getAndIncrement(), + 0); + if (t.isDaemon()) { + t.setDaemon(false); + } + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/ThreadPoolExecutorUtil.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/ThreadPoolExecutorUtil.java new file mode 100644 index 0000000..db542cf --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/config/thread/ThreadPoolExecutorUtil.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.config.thread; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * 用于获取自定义线程池 + * + * 2019年10月31日18:16:47 + */ +public class ThreadPoolExecutorUtil { + + public static ThreadPoolExecutor getPoll(){ + return new ThreadPoolExecutor( + AsyncTaskProperties.corePoolSize, + AsyncTaskProperties.maxPoolSize, + AsyncTaskProperties.keepAliveSeconds, + TimeUnit.SECONDS, + new ArrayBlockingQueue<>(AsyncTaskProperties.queueCapacity), + new TheadFactoryName() + ); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/controller/DnsController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/controller/DnsController.java new file mode 100644 index 0000000..581a46b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/controller/DnsController.java @@ -0,0 +1,48 @@ +package com.example.modules.dns.controller; + +import com.example.modules.dns.service.DnsService; +import com.example.utils.page.PageUtils; +import com.example.utils.page.R; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.text.DecimalFormat; +import java.util.Map; + +@RestController +@RequestMapping("/dns") +public class DnsController { + @Autowired + private DnsService dnsService; + + @GetMapping + public R queryPage(@RequestParam Map<String, Object> params) { + long startTime = System.currentTimeMillis(); + PageUtils page =dnsService.queryPage(params); + long endTime = System.currentTimeMillis(); + DecimalFormat df = new DecimalFormat("0.000"); + String totalTime = df.format((float) (endTime - startTime) / 1000); + page.setTotalTime(Double.parseDouble(totalTime)); + return R.ok(page); + } + + + //区域数据统计 + @GetMapping("/dataCount") + public R dataCount(@RequestParam Map<String, Object> params) { + return R.ok(dnsService.dataCount(params)); + } + + //区域数据统计 + @GetMapping("/mapData") + public R mapData() { + return R.ok(dnsService.mapData()); + } + + + + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DnsType.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DnsType.java new file mode 100644 index 0000000..983c2ee --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DnsType.java @@ -0,0 +1,24 @@ + +package com.example.modules.dns.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + + +@Data +@TableName("dns_type") +public class DnsType implements Serializable { + + @TableId(type = IdType.AUTO) + private Long id; + + private String ip; + + private String type; + + private int epoch; + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DohAttribute.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DohAttribute.java new file mode 100644 index 0000000..5a772e2 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/DohAttribute.java @@ -0,0 +1,66 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.dns.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Data +@TableName("doh_attribute") +public class DohAttribute implements Serializable { + + @TableId(type = IdType.AUTO) + private Long id; + private String ip; + private Integer port; + private String host; + private String path; + private String method; + private Integer connectType; + private Integer statusCode; + private String repHeader; + private String repBody; + private Date timestamp; + + private String component; + + private int rounds; + + @TableField(exist = false) + private List<String> pathList; + + @TableField(exist = false) + private List<String> componentList; + + @TableField(exist = false) + private List<IpCert> ipCert; + + @TableField(exist = false) + private List<IpInformation> ipInformation; + + @TableField(exist = false) + private List<List<Vulnerability>> vulnerability; + @TableField(exist = false) + private List<String> tags; + + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ForwardDns.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ForwardDns.java new file mode 100644 index 0000000..5823a34 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ForwardDns.java @@ -0,0 +1,24 @@ + +package com.example.modules.dns.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + + +@Data +@TableName("forward_dns") +public class ForwardDns implements Serializable { + + @TableId(type = IdType.AUTO) + private Long id; + + private String forwarder; + + private String upstream; + + private int epoch; + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpCert.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpCert.java new file mode 100644 index 0000000..a7f88af --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpCert.java @@ -0,0 +1,51 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.dns.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.example.modules.system.domain.Dept; +import com.example.modules.system.domain.Job; +import com.example.modules.system.domain.Role; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.Set; + +/** + * 2018-11-22 + */ +@Data +@TableName("ip_cert") +public class IpCert implements Serializable { + + @TableId(type = IdType.AUTO) + private Long id; + + private String ip; + + private String port; + + private String certificate; + + private String ca; + + private Date timestamp; + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpInformation.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpInformation.java new file mode 100644 index 0000000..1c61eb5 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/IpInformation.java @@ -0,0 +1,75 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.dns.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * + * 2018-11-22 + */ +@Data +@TableName("ip_information") +public class IpInformation implements Serializable { + @TableId(type = IdType.AUTO) + private Long id; + + private String ip; + + private String country; + + private String province; + + private String city; + private String district; + private String provider; + private String isp; + private Integer asnumber; + private Date timestamp; + private String zipcode; + private String timezone; + + @TableField(exist = false) + private List<IpCert> ipCert; + + @TableField(exist = false) + private List<NonstandardDns> nonstandardDns; + + + @TableField(exist = false) + private DnsType dnsType; + + @TableField(exist = false) + private List<DohAttribute> dohAttribute; + + @TableField(exist = false) + private List<ForwardDns> forwardDns; + + @TableField(exist = false) + private ScanResult scanResult; + + @TableField(exist = false) + private Integer dnsTypeValue; + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/NonstandardDns.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/NonstandardDns.java new file mode 100644 index 0000000..11badef --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/NonstandardDns.java @@ -0,0 +1,28 @@ + +package com.example.modules.dns.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.io.Serializable; + + +/** + * + * 直接响DNS表 + */ +@Data + @TableName("nonstandard_dns") +public class NonstandardDns implements Serializable { + @TableId(type = IdType.AUTO) + private Long id; + + private String ip; + + private String record; + + private int epoch; + + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Result.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Result.java new file mode 100644 index 0000000..6047df6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Result.java @@ -0,0 +1,71 @@ +package com.example.modules.dns.domain; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Data +public class Result implements Serializable { + + private Long id; + private String ip; + + private String protocolType; + private String ipType; + + private Integer port; + private String host; + private String path; + private String method; + private Integer connectType; + private Integer statusCode; + private String repHeader; + private String repBody; + private Date timestamp; + private String component; + + + private Integer flags; + private Integer opcode; + private Integer qr; + //权威标志位 + private Integer aa; + //递归标志位 + private Integer ra; + private Integer rcode; + private String queryName; + private String queryResponse; + + //(预留)ipv4,ipv6,dnssec,tcp,udp等 + private Integer scanType; + + private Date time; + + private Integer epoch; + + private Integer rounds; + + + private Integer dnsType; + + private String uuid; + + private List<String> pathList; + + private List<String> componentList; + + private List<IpCert> ipCert; + + private List<Vulnerability> vulnerability; + + private List<String> tags; + + private IpInformation ipInformation; + + private List<? extends Object> banner; + + private List<? extends Object> httpContent; + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ScanResult.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ScanResult.java new file mode 100644 index 0000000..8d479dc --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/ScanResult.java @@ -0,0 +1,75 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.dns.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 2018-11-22 + */ +@Data +@TableName("scan_result") +public class ScanResult implements Serializable { + @TableId(type = IdType.AUTO) + private Long id; + + private String ip; + + private Integer flags; + + private Integer opcode; + + private Integer qr; + //权威标志位 + private Integer aa; + //递归标志位 + private Integer ra; + + private Integer rcode; + + private String queryName; + + private String queryResponse; + + private String component; + + private int epoch; + + private List<String> componentList; + //(预留)ipv4,ipv6,dnssec,tcp,udp等 + private Integer scanType; + + private Date time; + @TableField(exist = false) + private IpInformation IpInformation; + @TableField(exist = false) + private List<IpInformation> forwarderBanner; + @TableField(exist = false) + private Integer dnsType; + @TableField(exist = false) + private List<NonstandardDns> nonstandardBanner; + + @TableField(exist = false) + private List<String> tags; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Vulnerability.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Vulnerability.java new file mode 100644 index 0000000..b31ba3e --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/domain/Vulnerability.java @@ -0,0 +1,24 @@ +package com.example.modules.dns.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +@TableName("vulnerability") +public class Vulnerability implements Serializable { + + @TableId(type = IdType.AUTO) + private Long id; + + private String component; + + private String vulnerability; + + private Date timestamp; + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDo53Dao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDo53Dao.java new file mode 100644 index 0000000..0d1eee5 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDo53Dao.java @@ -0,0 +1,76 @@ +package com.example.modules.dns.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.example.modules.dns.domain.Result; +import com.example.modules.dns.domain.ScanResult; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Map; + +@Mapper +@Repository +public interface DnsDo53Dao extends BaseMapper<ScanResult> { + + List<Result> queryDo53Page(IPage page, @Param("params") Map<String, Object> params); + + int do53IpCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> do53ServiceCategoryCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> do53ProvinceCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> do53ProviderCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> do53ComponentCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> do53VulnerabilityCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> do53CountryCount(); + + List<Map<String, Object>> do53CountryMapCount(); + + + List<Map<String, Object>> do53WorldMapCount(); + + List<Map<String, Object>> do53ChinaMapCount(); + + int pageCount(@Param("params") Map<String, Object> params); + + List<Result> queryOpenRdns(@Param("params")Map<String, Object> params); + + int getCountByDnsType(@Param("dnsType")Integer dnsType,@Param("params") Map<String, Object> params); + + int getIndependentIpNum(@Param("dnsType")Integer dnsType, @Param("params")Map<String, Object> params); + + List<Result> selectScanResultByUnion(IPage page, @Param("params") Map<String, Object> params); + + Integer selectScanResultCountByUnion(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> getDohAndDo53SrvCategoryCount(@Param("params") Map<String, Object> params); + + /** + * 根据dnsType和其他参数统计ip省份分布 + * @param dnsType + * @param params + * @return + */ + List<Map<String, Object>> getDo53ProvinceCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map<String, Object> params); + + /** + * 根据dnsType和其他参数统计ip运营商分布 + * @param dnsType + * @param params + * @return + */ + List<Map<String, Object>> getDo53ProviderCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map<String, Object> params); + + List<Map<String, Object>> getDo53ComponentCountByDnsType(@Param("dnsType") Integer dnsType, Map<String, Object> params); + + Integer getDo53SrvCategoryCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map<String, Object> params); + + List<Map<String, Object>> getDo53VulnerabCountByDnsType(@Param("dnsType") Integer dnsType, @Param("params") Map<String, Object> params); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDohDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDohDao.java new file mode 100644 index 0000000..29018e6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsDohDao.java @@ -0,0 +1,93 @@ +package com.example.modules.dns.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.example.modules.dns.domain.DohAttribute; +import com.example.modules.dns.domain.IpInformation; +import com.example.modules.dns.domain.Result; +import com.example.modules.dns.domain.ScanResult; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Map; + +@Mapper +@Repository +public interface DnsDohDao extends BaseMapper<DohAttribute> { + + List<Result> queryDohPage(IPage page, @Param("params") Map<String, Object> params); + + //省份数据统计 + List<Map<String, Object>> dohProvinceCount(@Param("params") Map<String, Object> params); + + int dohIpCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> dohPortCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> dohAndDo53ProvinceCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> dohProviderCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> dohAndDo53ProviderCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> dohComponentCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> dohAndDo53ComponentCount(@Param("params") Map<String, Object> params); + + Map<String, Object> dohServiceCategoryCount(@Param("params") Map<String, Object> params); + + int dohResultTotalCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> dohVulnerabilityCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> dohAndDo53VulnerabilityCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> dohCountryCount(); + + List<Map<String, Object>> dohChinaMapCount(); + + List<Result> getDohRepBody(String ip, Integer port, String host, Integer rounds); + + List<Result> selectDohInfoByUnion(@Param("params") Map<String, Object> params); + + Integer selectDohCountByUnion(@Param("params") Map<String, Object> params); + + /** + * 查询 doh 和 do53 交集下的port ip数量 + * @param params + * @return + */ + List<Map<String, Object>> countDohPortUnion(@Param("params") Map<String, Object> params); + + /** + * 统计 doh和do53公共ip的省份分布 + * @param params + * @return + */ + List<Map<String, Object>> getDohAndDo53ProvinceCount(@Param("params") Map<String, Object> params); + + /** + * 统计 doh和do53公共ip的运营商分布 + * @param params + * @return + */ + List<Map<String, Object>> getDohAndDo53ProviderCount(@Param("params") Map<String, Object> params); + + /** + * 统计 doh和do53公共ip的组件分布 + * @param params + * @return + */ + List<Map<String, Object>> getDohAndDo53ComponentCount(@Param("params") Map<String, Object> params); + + /** + * 统计 doh 和 do53公共ip 服务类别统计 + * @param params + * @return + */ + Map<String, Object> getDohServiceCategoryCount(@Param("params") Map<String, Object> params); + + List<Map<String, Object>> getDohAndDo53VulnerabilityCount(@Param("params") Map<String, Object> params); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsTypeDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsTypeDao.java new file mode 100644 index 0000000..e5193e6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/DnsTypeDao.java @@ -0,0 +1,20 @@ +package com.example.modules.dns.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.example.modules.dns.domain.DnsType; +import com.example.modules.dns.domain.DohAttribute; +import com.example.modules.dns.domain.IpCert; +import com.example.modules.dns.domain.ScanResult; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Map; + +@Mapper +@Repository +public interface DnsTypeDao extends BaseMapper<DnsType> { + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/ForwardDnsDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/ForwardDnsDao.java new file mode 100644 index 0000000..2986981 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/ForwardDnsDao.java @@ -0,0 +1,20 @@ +package com.example.modules.dns.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.example.modules.dns.domain.ForwardDns; +import com.example.modules.dns.domain.ScanResult; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Map; + +@Mapper +@Repository +public interface ForwardDnsDao extends BaseMapper<ForwardDns> { + + + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpCertDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpCertDao.java new file mode 100644 index 0000000..01939f6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpCertDao.java @@ -0,0 +1,32 @@ +package com.example.modules.dns.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.example.modules.dns.domain.DohAttribute; +import com.example.modules.dns.domain.IpCert; +import com.example.modules.dns.domain.ScanResult; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Map; + +@Mapper +@Repository +public interface IpCertDao extends BaseMapper<IpCert> { + + List<DohAttribute> queryDohPage(IPage page, @Param("params") Map<String, Object> params); + + // 国家数据统计 + List<Map<String, Object>> countryCount(); + + //省份数据统计 + List<Map<String, Object>> provinceCount(); + + // 城市数据统计 + List<Map<String, Object>> cityCount(); + + + List<ScanResult> queryDo53Page(IPage page, @Param("params") Map<String, Object> params); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpInformationDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpInformationDao.java new file mode 100644 index 0000000..2ed80e3 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/IpInformationDao.java @@ -0,0 +1,27 @@ +package com.example.modules.dns.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.example.modules.dns.domain.IpInformation; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Map; + +@Mapper +@Repository +public interface IpInformationDao extends BaseMapper<IpInformation> { + + + List<IpInformation> queryIpPage(IPage page, @Param("params") Map<String, Object> params); + + /** + * 根据 forward_dns中的 forwarder查询ip信息 + * @param ip + * @return + */ + List<IpInformation> getIpInfoByFwd(@Param("ip")String ip,@Param("epoch")Integer epoch); + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/NonstandardDnsDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/NonstandardDnsDao.java new file mode 100644 index 0000000..7c050ef --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/NonstandardDnsDao.java @@ -0,0 +1,15 @@ +package com.example.modules.dns.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.example.modules.dns.domain.ForwardDns; +import com.example.modules.dns.domain.NonstandardDns; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +@Mapper +@Repository +public interface NonstandardDnsDao extends BaseMapper<NonstandardDns> { + + + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/VulnerabilityDao.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/VulnerabilityDao.java new file mode 100644 index 0000000..5d1c06f --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/mapper/VulnerabilityDao.java @@ -0,0 +1,20 @@ +package com.example.modules.dns.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.example.modules.dns.domain.DohAttribute; +import com.example.modules.dns.domain.ScanResult; +import com.example.modules.dns.domain.Vulnerability; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Map; + +@Mapper +@Repository +public interface VulnerabilityDao extends BaseMapper<Vulnerability> { + + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsService.java new file mode 100644 index 0000000..3aad1ca --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsService.java @@ -0,0 +1,19 @@ +package com.example.modules.dns.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.example.modules.dns.domain.DohAttribute; +import com.example.modules.dns.domain.IpInformation; +import com.example.utils.page.PageUtils; + +import java.util.List; +import java.util.Map; + +public interface DnsService extends IService<DohAttribute> { + + + PageUtils queryPage(Map<String, Object> params); + + Map<String, Object> dataCount(Map<String, Object> params); + + Map<String, List<Map<String, Object>>> mapData(); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsTypeService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsTypeService.java new file mode 100644 index 0000000..f9cb1c6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/DnsTypeService.java @@ -0,0 +1,13 @@ +package com.example.modules.dns.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.example.modules.dns.domain.DnsType; +import com.example.modules.dns.domain.DohAttribute; +import com.example.utils.page.PageUtils; + +import java.util.List; +import java.util.Map; + +public interface DnsTypeService extends IService<DnsType> { + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/ScanResultService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/ScanResultService.java new file mode 100644 index 0000000..3dcd9dd --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/ScanResultService.java @@ -0,0 +1,13 @@ +package com.example.modules.dns.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.example.modules.dns.domain.ScanResult; + +import java.util.Map; + +public interface ScanResultService extends IService<ScanResult> { + + + Map<String, Object> queryDo53DataCountByDnsType(Map<String,Object> params,Integer dnsType); + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsQueryEnum.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsQueryEnum.java new file mode 100644 index 0000000..089a514 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsQueryEnum.java @@ -0,0 +1,108 @@ +package com.example.modules.dns.service.impl; + +import com.example.utils.Constant; +import com.example.utils.ElAdminConstant; + +import java.util.List; + +/** + * @author Lihe + * @version 1 + * @description 查询分类 + * @date 2022/6/22 + */ +public enum DnsQueryEnum { + + OPEN_RDNS(Constant.OPENRDNSTAG, ElAdminConstant.openRdnsLabels, "openRdns", 1), + + FORWARDER(Constant.FORWARDERTAG, ElAdminConstant.forwarderLabels, "forwarder", 2), + + FWD_RDNS(Constant.FWDRDNSTAG, ElAdminConstant.fwdRdnsLabels, "fwdRdns", 3), + + EGRESS_DNS(Constant.EGRESSRDNSTAG, ElAdminConstant.egressDnsLabels, "egressDns", 4), + + NON_STANDARD(Constant.NONSTANDARDTAG, ElAdminConstant.nonstandardLabels, "nonstandard", 5), + + DNS(Constant.DNSTAG, ElAdminConstant.dnsLabels, "queryDnsInfo", 0), + + DOH(Constant.DOH, ElAdminConstant.dohLabels, "queryDohInfo", 0), + + DO53(Constant.DO53, ElAdminConstant.do53Labels, "queryDo53Info", 0), + + DOH_AND_DO53("dohAndDo53", null, "queryDohAndDo53Info", 0), + + IP(Constant.IP, null, "queryPageByIp", 0), + ; + + private final String service; + + private final List<String> labels; + + private final String methodName; + + private final Integer dnsType; + + public static DnsQueryEnum getQueryInfo(String serviceName) { + for (DnsQueryEnum value : DnsQueryEnum.values()) { + if (value.getService().equals(serviceName)) { + return value; + } + } + return null; + } + + + public String getMethodName() { + return methodName; + } + + public String getService() { + return service; + } + + public List<String> getLabels() { + return labels; + } + + public Integer getDnsType() { + return dnsType; + } + + DnsQueryEnum(String service, List<String> labels, String methodName, Integer dnsType) { + this.service = service; + this.labels = labels; + this.methodName = methodName; + this.dnsType = dnsType; + } + + public static List<String> getLabels(String key) { + for (DnsQueryEnum value : DnsQueryEnum.values()) { + if (value.getService().equals(key)) { + return value.getLabels(); + } + } + return null; + } + + public static Integer getDnsType(String key) { + for (DnsQueryEnum value : DnsQueryEnum.values()) { + if (value.getService().equals(key)) { + return value.getDnsType(); + } + } + return null; + } + + public static String getDnsType(Integer type) { + for (DnsQueryEnum value : DnsQueryEnum.values()) { + if (value.getDnsType().equals(type)) { + return value.getService(); + } + } + return null; + } + +} + + + diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsServiceImpl.java new file mode 100644 index 0000000..09cab1a --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsServiceImpl.java @@ -0,0 +1,631 @@ +package com.example.modules.dns.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.example.modules.dns.domain.*; +import com.example.modules.dns.mapper.*; +import com.example.modules.dns.service.DnsService; +import com.example.modules.dns.service.ScanResultService; +import com.example.utils.Constant; +import com.example.utils.page.PageUtils; +import com.example.utils.page.Query; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class DnsServiceImpl extends ServiceImpl<DnsDohDao, DohAttribute> implements DnsService { + @Autowired + private DnsDohDao dnsDohDao; + + @Autowired + private DnsDo53Dao dnsDo53Dao; + + @Autowired + private IpCertDao ipCertDao; + + @Autowired + private IpInformationDao ipInformationDao; + + @Autowired + private NonstandardDnsDao nonstandardDnsDao; + + @Autowired + private ScanResultService scanResultService; + + + /** + * 添加新service查询逻辑时: + * 1. 在本类中实现该service的查询逻辑 + * 2. DnsQueryEnum 添加该查询逻辑的枚举,包括serviceName,方法名,标签和dnsType可根据需要设置 + * and 查询逻辑需要单独实现 + * @param params + * @return + */ + @Override + public PageUtils queryPage(Map<String, Object> params) { + String service = (String) params.get(Constant.SERVICE); + String port = (String) params.get(Constant.PORT); + String ip = (String) params.get(Constant.IP); + IPage page = new Query(IpInformation.class).getPage(params); + params.put("n", (page.getCurrent() - 1) * page.getSize()); //用作doh查询的分页 + params.put("m", page.getSize()); //用作doh查询的分页 + if(StringUtils.isBlank(service) && StringUtils.isBlank(ip) && StringUtils.isBlank(port)){ + return new PageUtils(page); + } + if(StringUtils.isNotBlank(port)){ + if(Constant.PORT53.equals(port)){ + service = Constant.DO53; + }else if(Constant.PORT443.equals(port) || Constant.PORT8443.equals(port)){ + service = Constant.DOH; + } + } + if(StringUtils.isBlank(port) && StringUtils.isBlank(service) && StringUtils.isNotBlank(ip)){ + service = Constant.IP; + } + if(StringUtils.isNotBlank(service)) { + if(service.toLowerCase().contains("and")){ + return queryDohAndDo53Info(page,params); + }else { + // DnsQueryEnum 枚举类获取service对应的方法名,并通过反射调用 + DnsQueryEnum serviceEnum = DnsQueryEnum.getQueryInfo(service.toLowerCase()); + Class<? extends DnsServiceImpl> aClass = this.getClass(); + try { + Method method = aClass.getDeclaredMethod(serviceEnum.getMethodName(), IPage.class, Map.class); + return (PageUtils) method.invoke(this, page, params); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return new PageUtils(page); + } + + @Override + public Map<String, Object> dataCount(Map<String, Object> params) { + String service = (String) params.get(Constant.SERVICE); + String port = (String) params.get(Constant.PORT); + String ip = (String) params.get(Constant.IP); + Map<String, Object> resultMap = new HashMap(8); + if(StringUtils.isBlank(service) && StringUtils.isBlank(ip) && StringUtils.isBlank(port)){ + return resultMap; + } + List<Map<String, Object>> portList = new ArrayList<>(); + List<Map<String, Object>> regionList ; + List<Map<String, Object>> providerList ; + List<Map<String, Object>> componentList ; + List<Map<String, Object>> serviceCategoryList = new ArrayList<>(); + List<Map<String, Object>> do53serviceCategoryList ; + List<Map<String, Object>> vulnerabilityCountList ; + if (Constant.DOH.equals(service) || Constant.PORT8443.equals(port) || Constant.PORT443.equals(port)) { + //端口 + portList = dnsDohDao.dohPortCount(params); + //地域 + regionList = dnsDohDao.dohProvinceCount(params); + //运营商 + providerList = dnsDohDao.dohProviderCount(params); + //服务组件 + componentList = dnsDohDao.dohComponentCount(params); + //服务类别 + Map<String, Object> map = dnsDohDao.dohServiceCategoryCount(params); + map.put("key", Constant.DOHTAG); + serviceCategoryList.add(map); + //漏洞威胁 + vulnerabilityCountList = dnsDohDao.dohVulnerabilityCount(params); + + } else if (Constant.DO53.equals(service) || Constant.PORT53.equals(port)) { + //端口 + Map<String, Object> portMap = new HashMap<>(); + int do53PortCount = dnsDo53Dao.do53IpCount(params); + portMap.put("port", Constant.PORT53); + portMap.put("count", do53PortCount); + portList.add(portMap); + //地域 + regionList = dnsDo53Dao.do53ProvinceCount(params); + //运营商 + providerList = dnsDo53Dao.do53ProviderCount(params); + //服务组件 + componentList = dnsDo53Dao.do53ComponentCount(params); + //服务类别 + do53serviceCategoryList = dnsDo53Dao.do53ServiceCategoryCount(params); + serviceCategoryList = transformDo53serviceCategory(do53serviceCategoryList); + //漏洞威胁 + vulnerabilityCountList = dnsDo53Dao.do53VulnerabilityCount(params); + + }else if ("dns".equalsIgnoreCase(service) || StringUtils.isNotBlank(ip)) { + //端口 + portList = dnsDohDao.dohPortCount(params); + Map<String, Object> portMap = new HashMap<>(); + Integer do53PortCount = dnsDo53Dao.do53IpCount(params); + portMap.put("port", Constant.PORT53); + portMap.put("count", do53PortCount); + portList.add(portMap); + //地域 + regionList = dnsDohDao.dohAndDo53ProvinceCount(params); + //运营商 + providerList = dnsDohDao.dohAndDo53ProviderCount(params); + //服务组件 + componentList = dnsDohDao.dohAndDo53ComponentCount(params); + //服务类别 + do53serviceCategoryList = dnsDo53Dao.do53ServiceCategoryCount(params); + serviceCategoryList = transformDo53serviceCategory(do53serviceCategoryList); + Map<String, Object> map = dnsDohDao.dohServiceCategoryCount(params); + map.put("key", Constant.DOHTAG); + serviceCategoryList.add(map); + //漏洞威胁 + vulnerabilityCountList = dnsDohDao.dohAndDo53VulnerabilityCount(params); + }else if(service.toLowerCase().contains("and")){ + // 目前只有 doh AND do53其余条件未实现 + //端口 + portList = dnsDohDao.countDohPortUnion(params); + + //地域 + regionList = dnsDohDao.getDohAndDo53ProvinceCount(params); + //运营商 + providerList = dnsDohDao.getDohAndDo53ProviderCount(params); + //服务组件 + componentList = dnsDohDao.getDohAndDo53ComponentCount(params); + //服务类别 + do53serviceCategoryList = dnsDo53Dao.getDohAndDo53SrvCategoryCount(params); + serviceCategoryList = transformDo53serviceCategory(do53serviceCategoryList); + Map<String, Object> map = dnsDohDao.getDohServiceCategoryCount(params); + map.put("key", Constant.DOHTAG); + map.put("count", dnsDo53Dao.selectScanResultCountByUnion(params)); + serviceCategoryList.add(map); + //漏洞威胁 + vulnerabilityCountList = dnsDohDao.getDohAndDo53VulnerabilityCount(params); + }else{ + // dn53下5种 dns_type 统计 + return scanResultService.queryDo53DataCountByDnsType(params,DnsQueryEnum.getDnsType(service)); + } + resultMap.put("portList", portList); + resultMap.put("regionList", regionList); + resultMap.put("providerList", providerList); + resultMap.put("componentList", componentList); + resultMap.put("serviceCategoryList", serviceCategoryList); + resultMap.put("vulnerabilityCountList", vulnerabilityCountList); + return resultMap; + } + + @Override + public Map<String, List<Map<String, Object>>> mapData() { + Map<String, List<Map<String, Object>>> resultMap = new HashMap<>(); + List<Map<String, Object>> dohChinaMapList ; + List<Map<String, Object>> dohWorldMapDataList ; + List<Map<String, Object>> do53CountryMapCountList ; + List<Map<String, Object>> do53OpenRdnsList = new ArrayList<>(); + List<Map<String, Object>> do53ForwarderList = new ArrayList<>(); + List<Map<String, Object>> do53FwdRdnsList = new ArrayList<>(); + List<Map<String, Object>> do53EgressDnsList = new ArrayList<>(); + List<Map<String, Object>> do53NonstandardList = new ArrayList<>(); + List<Map<String, Object>> do53WorldMapList ; + List<Map<String, Object>> do53ChinaMapList ; + dohChinaMapList = dnsDohDao.dohChinaMapCount(); + dohWorldMapDataList = dnsDohDao.dohCountryCount(); + do53WorldMapList = dnsDo53Dao.do53WorldMapCount(); + do53ChinaMapList = dnsDo53Dao.do53ChinaMapCount(); + do53CountryMapCountList = dnsDo53Dao.do53CountryMapCount(); + for (Map<String, Object> map : do53CountryMapCountList) { + if (Constant.OPENRDNS == map.get("type")) { + do53OpenRdnsList.add(map); + } else if (Constant.FORWARDER == map.get("type")) { + do53ForwarderList.add(map); + } else if (Constant.FWDRDNS == map.get("type")) { + do53FwdRdnsList.add(map); + } else if (Constant.EGRESSRDNS == map.get("type")) { + do53EgressDnsList.add(map); + } else if (Constant.NONSTANDARD == map.get("type")) { + do53NonstandardList.add(map); + } + } + resultMap.put("dohChinaMapList", dohChinaMapList); + resultMap.put("dohWorldMapDataList", dohWorldMapDataList); + resultMap.put("do53WorldMapDataList", do53WorldMapList); + resultMap.put("do53ChinaMapList", do53ChinaMapList); + resultMap.put("do53OpenRdnsList", do53OpenRdnsList); + resultMap.put("do53ForwarderList", do53ForwarderList); + resultMap.put("do53FwdRdnsList", do53FwdRdnsList); + resultMap.put("do53EgressDnsList", do53EgressDnsList); + resultMap.put("do53NonstandardList", do53NonstandardList); + return resultMap; + } + + public List<Map<String, Object>> transformDo53serviceCategory(List<Map<String, Object>> do53serviceCategoryList) { + List<Map<String, Object>> serviceCategoryList = new ArrayList<>(); + long do53Count = 0; + for (Map<String, Object> map : do53serviceCategoryList) { + Map<String, Object> do53ServiceMap = new HashMap<>(); + long count = (long) map.get("count"); + int dnsType = (int) map.get("type"); + if (Constant.FORWARDER == dnsType) { //2 + do53ServiceMap.put("key", Constant.FORWARDERTAG); + do53ServiceMap.put("count", count); + } else if (Constant.FWDRDNS == dnsType) {//3 + do53ServiceMap.put("key", Constant.FWDRDNSTAG); + do53ServiceMap.put("count", count); + } else if (Constant.EGRESSRDNS == dnsType) { //4 + do53ServiceMap.put("key", Constant.EGRESSRDNSTAG); + do53ServiceMap.put("count", count); + } else if (Constant.NONSTANDARD == dnsType) { //5 + do53ServiceMap.put("key", Constant.NONSTANDARDTAG); + do53ServiceMap.put("count", count); + } else if (Constant.OPENRDNS == dnsType) { //1 + do53ServiceMap.put("key", Constant.OPENRDNSTAG); + do53ServiceMap.put("count", count); + } + do53Count += count; + serviceCategoryList.add(do53ServiceMap); + } + HashMap<String, Object> do53Map = new HashMap<>(); + do53Map.put("key", Constant.DO53TAG); + do53Map.put("count", do53Count); + serviceCategoryList.add(do53Map); + return serviceCategoryList; + + } + + /** + * 设置doh属性 + * @param dohAttributes + */ + public void setDohData(List<Result> dohAttributes) { + for (Result dohAttribute : dohAttributes) { + String uuid = UUID.randomUUID().toString().trim().replaceAll("-", ""); + dohAttribute.setUuid(uuid); + String dohIp = dohAttribute.getIp(); + Integer port = dohAttribute.getPort(); + String component = dohAttribute.getComponent(); + String path = dohAttribute.getPath(); + dohAttribute.setProtocolType(Constant.PROTOC_TCP); + dohAttribute.setIpType(getIpType(dohIp)); + if (component != null) + dohAttribute.setComponentList(new ArrayList<>(Arrays.stream(component.split(",")).collect(Collectors.toSet()))); + if (path != null) + dohAttribute.setPathList(new ArrayList<>(Arrays.stream(path.split(",")).collect(Collectors.toSet()))); + ArrayList<String> tagList = new ArrayList<>(); //添加服务类别标签 + tagList.add(Constant.DOHTAG); + List<Object> banner = new ArrayList<>(); + List<Object> httpHeader = new ArrayList<>(); + // 根据ip,port,host,rounds查询doh_attribute rep_body repHeader信息 + List<Result> repList = this.baseMapper.getDohRepBody(dohIp, port, dohAttribute.getHost(), dohAttribute.getRounds()); + for (int i = 0; i < repList.size(); i++) { + Result result = repList.get(i); + if (StringUtils.isNotBlank(result.getRepBody())) { + banner.add(result.getRepBody()); + } + if (StringUtils.isNotBlank(result.getRepHeader())) { + httpHeader.add(result.getRepHeader()); + } + } + dohAttribute.setBanner(banner); + dohAttribute.setHttpContent(httpHeader); + //根据ip和端口查询证书库,获取证书数据 + List<IpCert> ipCertList = ipCertDao.selectList(new LambdaQueryWrapper<IpCert>().eq(IpCert::getIp, dohIp).eq(IpCert::getPort, port)); + dohAttribute.setIpCert(ipCertList); + dohAttribute.setTags(tagList); + } + } + + /** + * 设置do53标签,根据dnsType设置banner + * type = 1 banner list.get(0)为rep + * type = 2,3 banner中的 list.get(0)为 query_rep,列表其余数据为ip信息 + * type = 5 banner list.get(0)为rep,其余为NonstandardDns列表 + * @param scanResultList + */ + public void setdo53Data(List<Result> scanResultList) { + for (Result scanResult : scanResultList) { + String uuid = UUID.randomUUID().toString().trim().replaceAll("-", ""); + scanResult.setUuid(uuid); + String do53Ip = scanResult.getIp(); + Integer epoch = scanResult.getEpoch(); + Integer dnsType = scanResult.getDnsType(); + ArrayList<String> tagList = new ArrayList<>(); //添加服务类别标签 + tagList.add(Constant.DO53TAG); + scanResult.setIpType(getIpType(do53Ip)); + scanResult.setProtocolType(getProtocolType(scanResult.getScanType())); + List<Object> bannerList = new ArrayList<>(); + if (Constant.FORWARDER.equals(dnsType) || Constant.FWDRDNS.equals(dnsType)) { //2、3 + if (Constant.FWDRDNS.equals(dnsType)) { //3 + tagList.add(Constant.FORWARDERTAG); + } else { + tagList.add(Constant.FWDRDNSTAG); + } + bannerList.add(scanResult.getQueryResponse()); + List<IpInformation> forwardDnsList = ipInformationDao.getIpInfoByFwd(do53Ip, epoch); + bannerList.addAll(forwardDnsList); + } else if (Constant.EGRESSRDNS.equals(dnsType)) { //4 + tagList.add(Constant.EGRESSRDNSTAG); + + } else if (Constant.NONSTANDARD.equals(dnsType)) { //5 + bannerList.add(scanResult.getQueryResponse()); + tagList.add(Constant.NONSTANDARDTAG); + List<NonstandardDns> nonstandardDnsList = nonstandardDnsDao.selectList(new LambdaQueryWrapper<NonstandardDns>().eq(NonstandardDns::getIp, do53Ip).eq(NonstandardDns::getEpoch, epoch)); + bannerList.addAll((List<JSONObject>) JSONObject.toJSON(nonstandardDnsList)); + } else if (Constant.OPENRDNS.equals(dnsType)) { //1 + tagList.add(Constant.OPENRDNSTAG); + if(StringUtils.isNotBlank(scanResult.getQueryResponse())){ + bannerList.add(scanResult.getQueryResponse()); + } + } + scanResult.setBanner(bannerList); + scanResult.setTags(tagList); + } + } + + /** + * @param dataList 目标list + * @param pageSize 当前页大小 + * @param currentPage 当前页 + * @return 返回当前页的数据集 + * @deprecated 对list进行分页 + */ + public List<Result> getPage(List<Result> dataList, int pageSize, int currentPage) { + List<Result> currentPageList = new ArrayList<>(); + if (!dataList.isEmpty()) { + int currIdx = (currentPage > 1 ? (currentPage - 1) * pageSize : 0); + for (int i = 0; i < pageSize && i < dataList.size() - currIdx; i++) { + Result data = dataList.get(currIdx + i); + currentPageList.add(data); + } + } + return currentPageList; + } + + + /** + * 查询dns信息,dnh和do53(scan_result)结果并集 + * + * @param page + * @param params + * @return + */ + private PageUtils queryDnsInfo(IPage page, Map<String, Object> params) { + Map<String, Object> indepentIpMap = new HashMap<>(4); + int resultTotal = 0; + long pageSize = page.getSize(); + params.put("n", 0); //用作doh查询的分页偏移量 + params.put("m", page.getCurrent() * page.getSize()); //用作查询的分页大小 + // 查询doh信息 + //同一轮次,相同ip合并path和component,漏洞信息 + List<Result> dohAttributes = dnsDohDao.queryDohPage(null, params); + setDohData(dohAttributes); + int dohResultTotal = dnsDohDao.dohResultTotalCount(params); + indepentIpMap.put("dns-doh", dnsDohDao.dohIpCount(params)); + // 查询do53信息 + List<Result> scanResultList = dnsDo53Dao.queryDo53Page(null, params); + setdo53Data(scanResultList); + indepentIpMap.put("dns-do53", dnsDo53Dao.do53IpCount(params)); + int do53ResultTotal = dnsDo53Dao.pageCount(params); + + List<Result> resultList = new ArrayList<>(); + resultList.addAll(dohAttributes); + resultList.addAll(scanResultList); + List<Result> collect = resultList.stream().sorted(Comparator.comparing(Result::getTimestamp).reversed()).collect(Collectors.toList()); + + page.setTotal(do53ResultTotal + dohResultTotal); + page.setRecords(getPage(collect, (int) pageSize, (int) page.getCurrent())); + + return buildResult(page,indepentIpMap,(do53ResultTotal + dohResultTotal)); + } + + /** + * 查询 do53信息 + * @param page + * @param params + * @return + */ + private PageUtils queryDo53Info(IPage page, Map<String, Object> params){ + // 根据 service=dns-do53, port为53查询 scan_result表 参数:ip,port + List<Result> scanResultList = dnsDo53Dao.queryDo53Page(null, params); + setdo53Data(scanResultList); + + int independentIpNum = dnsDo53Dao.do53IpCount(params); + int resultTotal = dnsDo53Dao.pageCount(params); + page.setRecords(scanResultList); + return buildResult(page,independentIpNum,resultTotal); + } + + /** + * 查询doh信息 + * @param page + * @param params + * @return + */ + private PageUtils queryDohInfo(IPage page, Map<String, Object> params){ + // 根据 service=dns-do53, port为53查询 scan_result表 参数:ip,port + List<Result> scanResultList = dnsDohDao.queryDohPage(null, params); + setDohData(scanResultList); + + int independentIpNum = dnsDohDao.dohIpCount(params); + int resultTotal = dnsDohDao.dohResultTotalCount(params); + page.setRecords(scanResultList); + return buildResult(page,independentIpNum,resultTotal); + } + + /** + * 只根据ip查询 + * @param page + * @param params + * @return + */ + private PageUtils queryPageByIp(IPage page, Map<String, Object> params){ + // 只根据ip查询 + int independentIpNum = 0; + params.put("n", 0); //用作doh查询的分页 + params.put("m", page.getCurrent() * page.getSize()); //用作doh查询的分页 + long pageSize = page.getSize(); + List<Result> dohAttributesList = dnsDohDao.queryDohPage(null, params); + setDohData(dohAttributesList); + List<Result> scanResultList = dnsDo53Dao.queryDo53Page(null, params); + setdo53Data(scanResultList); + List<Result> resultList = new ArrayList<>(); + resultList.addAll(dohAttributesList); + resultList.addAll(scanResultList); + int resultTotal = resultList.size(); + List<Result> collect = resultList.stream().sorted(Comparator.comparing(Result::getTimestamp).reversed()).collect(Collectors.toList()); + if (!collect.isEmpty()) { + independentIpNum = 1; + } + page.setTotal(collect.size()); + page.setRecords(getPage(collect, (int) pageSize, (int) page.getCurrent())); + return buildResult(page,independentIpNum,resultTotal); + } + + /** + * 查询 dnh和do53(scan_result)结果交集 service = dns-doh AND dns-do53 + * + * @param page + * @param params + * @return + */ + private PageUtils queryDohAndDo53Info(IPage page, Map<String, Object> params) { + params.put("offset", 0); //用作doh查询的分页偏移量 + params.put("limit", page.getCurrent() * page.getSize()); //用作查询的分页大小 + Map<String, Object> indepentIpMap = new HashMap<>(4); + + // 查询doh信息 + List<Result> dohAttributes = dnsDohDao.selectDohInfoByUnion(params); + Integer dohCount = dnsDohDao.selectDohCountByUnion(params); + setDohData(dohAttributes); + // 查询do53(scan_result)信息 + List<Result> do53Infos = dnsDo53Dao.selectScanResultByUnion(null,params); + Integer do53Count = dnsDo53Dao.selectScanResultCountByUnion(params); + setdo53Data(do53Infos); + do53Infos.addAll(dohAttributes); + + page.setTotal(dohCount + do53Count); + page.setRecords(getPage(do53Infos, (int) page.getSize(), (int) page.getCurrent())); + indepentIpMap.put("dns-doh",do53Count); + indepentIpMap.put("dns-do53",do53Count); + + return buildResult(page,indepentIpMap,(dohCount + do53Count)); + + } + + private String getIpType(String ip){ + if(ip.contains(Constant.POINT)){ + return Constant.IP_IPV4; + } + return Constant.IP_IPV6; + } + + private String getProtocolType(Integer scanType){ + // dnsType 为2为udp,1或者空为tcp + if(scanType == null || scanType < 2){ + return Constant.PROTOC_TCP; + } + return Constant.PROTOC_UDP; + } + + private PageUtils buildResult(IPage page,Object independentIpNum,Integer resultTotal ){ + PageUtils pageUtils = new PageUtils(page); + // 添加独立IP个数 + pageUtils.setIndependentIpNum(independentIpNum); + pageUtils.setResultTotal(resultTotal); + return pageUtils; + } + + + private PageUtils openRdns(IPage page, Map<String, Object> params) { + List<Result> results = dnsDo53Dao.queryOpenRdns(params); + int totalCount = dnsDo53Dao.getCountByDnsType(Constant.OPENRDNS, params); + setDo53Label(results, Constant.OPENRDNSTAG); + page.setRecords(results); + // 添加独立IP个数 + Integer independentIpNum = dnsDo53Dao.getIndependentIpNum(Constant.OPENRDNS, params); + + return buildResult(page,independentIpNum,totalCount); + } + + private PageUtils forwarder(IPage page, Map<String, Object> params) { + int totalCount = dnsDo53Dao.getCountByDnsType(Constant.FORWARDER, params); + List<Result> results = dnsDo53Dao.queryOpenRdns(params); + for (Result result : results) { + List<IpInformation> ipInfos = ipInformationDao.getIpInfoByFwd(result.getIp(),null); + result.setBanner(ipInfos); + result.setProtocolType(getProtocolType(result.getScanType())); + result.setIpType(getIpType(result.getIp())); + addLabels(result, Constant.FORWARDERTAG); + } + + page.setRecords(results); + // 添加独立IP个数 + Integer independentIpNum = dnsDo53Dao.getIndependentIpNum(Constant.FORWARDER, params); + + return buildResult(page,independentIpNum,totalCount); + } + + private PageUtils fwdRdns(IPage page, Map<String, Object> params) { + int totalCount = dnsDo53Dao.getCountByDnsType(Constant.FWDRDNS, params); + List<Result> results = dnsDo53Dao.queryOpenRdns(params); + for (Result result : results) { + List<IpInformation> ipInfos = ipInformationDao.getIpInfoByFwd(result.getIp(),null); + result.setBanner(ipInfos); + result.setProtocolType(getProtocolType(result.getScanType())); + result.setIpType(getIpType(result.getIp())); + addLabels(result, Constant.FWDRDNSTAG); + } + page.setRecords(results); + // 添加独立IP个数 + Integer independentIpNum = dnsDo53Dao.getIndependentIpNum(Constant.FWDRDNS, params); + + return buildResult(page,independentIpNum,totalCount); + } + + private PageUtils egressDns(IPage page, Map<String, Object> params) { + int totalCount = dnsDo53Dao.getCountByDnsType(Constant.EGRESSRDNS, params); + List<Result> results = dnsDo53Dao.queryOpenRdns(params); + setDo53Label(results, Constant.EGRESSRDNSTAG); + page.setRecords(results); + // 添加独立IP个数 + Integer independentIpNum = dnsDo53Dao.getIndependentIpNum(Constant.EGRESSRDNS, params); + + return buildResult(page,independentIpNum,totalCount); + } + + private PageUtils nonstandard(IPage page, Map<String, Object> params) { + int totalCount = dnsDo53Dao.getCountByDnsType(Constant.NONSTANDARD, params); + List<Result> results = dnsDo53Dao.queryOpenRdns(params); + for (Result result : results) { + List<IpInformation> ipInfos = ipInformationDao.getIpInfoByFwd(result.getIp(),null); + result.setBanner(ipInfos); + result.setProtocolType(getProtocolType(result.getScanType())); + result.setIpType(getIpType(result.getIp())); + addLabels(result, Constant.NONSTANDARDTAG); + } + + page.setRecords(results); + // 添加独立IP个数 + Integer independentIpNum = dnsDo53Dao.getIndependentIpNum(Constant.NONSTANDARD, params); + + return buildResult(page,independentIpNum,totalCount); + } + + + + private void setDo53Label(List<Result> results, String serviceType) { + List<String> labels = DnsQueryEnum.getLabels(serviceType); + for (Result result : results) { + // result.setBanner(result.getQueryResponse()); + result.setProtocolType(getProtocolType(result.getScanType())); + result.setIpType(getIpType(result.getIp())); + result.setTags(labels); + } + } + + private void addLabels(Result result, String serviceType) { + List<String> labels = DnsQueryEnum.getLabels(serviceType); + result.setTags(labels); + } + +} + + + diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsTypeServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsTypeServiceImpl.java new file mode 100644 index 0000000..8bd6d89 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/DnsTypeServiceImpl.java @@ -0,0 +1,15 @@ +package com.example.modules.dns.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.example.modules.dns.domain.DnsType; +import com.example.modules.dns.mapper.DnsTypeDao; +import com.example.modules.dns.service.DnsTypeService; +import org.springframework.stereotype.Service; + +@Service +public class DnsTypeServiceImpl extends ServiceImpl<DnsTypeDao, DnsType> implements DnsTypeService { + +} + + + diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/ScanResultServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/ScanResultServiceImpl.java new file mode 100644 index 0000000..5b832c9 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/dns/service/impl/ScanResultServiceImpl.java @@ -0,0 +1,66 @@ +package com.example.modules.dns.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.example.modules.dns.domain.ScanResult; +import com.example.modules.dns.mapper.DnsDo53Dao; +import com.example.modules.dns.service.ScanResultService; +import com.example.utils.Constant; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Lihe + * @version 1 + * @description + * @date 2022/6/8 + */ +@Service +public class ScanResultServiceImpl extends ServiceImpl<DnsDo53Dao, ScanResult> implements ScanResultService { + + + @Override + public Map<String, Object> queryDo53DataCountByDnsType(Map<String, Object> params, Integer dnsType) { + + Map<String, Object> resultMap = new HashMap(8); + List<Map<String, Object>> portList = new ArrayList<>(); + + List<Map<String, Object>> serviceCategoryList = new ArrayList<>(); + //端口 + Map<String, Object> portMap = new HashMap<>(); + int count = this.baseMapper.getCountByDnsType(dnsType,params); + portMap.put("port", Constant.PORT53); + portMap.put("count", count); + portList.add(portMap); + resultMap.put("portList", portList); + + //地域 + resultMap.put("regionList", this.baseMapper.getDo53ProvinceCountByDnsType(dnsType,params)); + + //运营商 + resultMap.put("providerList", this.baseMapper.getDo53ProviderCountByDnsType(dnsType,params)); + + //服务组件 + resultMap.put("componentList", this.baseMapper.getDo53ComponentCountByDnsType(dnsType,params)); + + //服务类别 + Integer serviceCount = this.baseMapper.getDo53SrvCategoryCountByDnsType(dnsType,params); + Map<String,Object> dnsTypeMap = new HashMap<>(2); + dnsTypeMap.put("key",DnsQueryEnum.getDnsType(dnsType)); + dnsTypeMap.put("count",serviceCount); + serviceCategoryList.add(dnsTypeMap); + Map<String,Object> do53ServiceMap = new HashMap<>(2); + do53ServiceMap.put("key",Constant.DO53TAG); + do53ServiceMap.put("count",serviceCount); + serviceCategoryList.add(do53ServiceMap); + resultMap.put("serviceCategoryList", serviceCategoryList); + + //漏洞威胁 + resultMap.put("vulnerabilityCountList", this.baseMapper.getDo53VulnerabCountByDnsType(dnsType,params)); + + return resultMap; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/ConfigBeanConfiguration.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/ConfigBeanConfiguration.java new file mode 100644 index 0000000..1c01c10 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/ConfigBeanConfiguration.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.config; + +import com.example.modules.security.config.bean.LoginProperties; +import com.example.modules.security.config.bean.SecurityProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @apiNote 配置文件转换Pojo类的 统一配置 类 + * @author: liaojinlong + * : 2020/6/10 19:04 + */ +@Configuration +public class ConfigBeanConfiguration { + + @Bean + @ConfigurationProperties(prefix = "login") + public LoginProperties loginProperties() { + return new LoginProperties(); + } + + @Bean + @ConfigurationProperties(prefix = "jwt") + public SecurityProperties securityProperties() { + return new SecurityProperties(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/SpringSecurityConfig.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/SpringSecurityConfig.java new file mode 100644 index 0000000..aa9fddf --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/SpringSecurityConfig.java @@ -0,0 +1,192 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.config; + +import com.example.modules.security.security.JwtAccessDeniedHandler; +import com.example.modules.security.security.JwtAuthenticationEntryPoint; +import com.example.modules.security.security.TokenConfigurer; +import com.example.modules.security.security.TokenProvider; +import lombok.RequiredArgsConstructor; +import com.example.annotation.AnonymousAccess; +import com.example.modules.security.config.bean.SecurityProperties; +import com.example.modules.security.security.*; +import com.example.modules.security.service.OnlineUserService; +import com.example.modules.security.service.UserCacheClean; +import com.example.utils.enums.RequestMethodEnum; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.core.GrantedAuthorityDefaults; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import java.util.*; + +/** + * + */ +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { + + private final TokenProvider tokenProvider; + private final CorsFilter corsFilter; + private final JwtAuthenticationEntryPoint authenticationErrorHandler; + private final JwtAccessDeniedHandler jwtAccessDeniedHandler; + private final ApplicationContext applicationContext; + private final SecurityProperties properties; + private final OnlineUserService onlineUserService; + private final UserCacheClean userCacheClean; + + @Bean + GrantedAuthorityDefaults grantedAuthorityDefaults() { + // 去除 ROLE_ 前缀 + return new GrantedAuthorityDefaults(""); + } + + @Bean + public PasswordEncoder passwordEncoder() { + // 密码加密方式 + return new BCryptPasswordEncoder(); + } + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + // 搜寻匿名标记 url: @AnonymousAccess + RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping"); + Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods(); + // 获取匿名标记 + Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap); + httpSecurity + // 禁用 CSRF + .csrf().disable() + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) + // 授权异常 + .exceptionHandling() + .authenticationEntryPoint(authenticationErrorHandler) + .accessDeniedHandler(jwtAccessDeniedHandler) + // 防止iframe 造成跨域 + .and() + .headers() + .frameOptions() + .disable() + // 不创建会话 + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 静态资源等等 + .antMatchers( + HttpMethod.GET, + "/*.html", + "/**/*.html", + "/**/*.css", + "/**/*.js", + "/webSocket/**" + ).permitAll() + // swagger 文档 + .antMatchers("/swagger-ui.html").permitAll() + .antMatchers("/swagger-resources/**").permitAll() + .antMatchers("/webjars/**").permitAll() + .antMatchers("/*/api-docs").permitAll() + // 文件 + .antMatchers("/avatar/**").permitAll() + .antMatchers("/file/**").permitAll() + // 阿里巴巴 druid + .antMatchers("/druid/**").permitAll() + // 放行OPTIONS请求 + .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() + // 自定义匿名访问所有url放行:允许匿名和带Token访问,细腻化到每个 Request 类型 + // GET + .antMatchers(HttpMethod.GET, anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray(new String[0])).permitAll() + // POST + .antMatchers(HttpMethod.POST, anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray(new String[0])).permitAll() + // PUT + .antMatchers(HttpMethod.PUT, anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray(new String[0])).permitAll() + // PATCH + .antMatchers(HttpMethod.PATCH, anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray(new String[0])).permitAll() + // DELETE + .antMatchers(HttpMethod.DELETE, anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray(new String[0])).permitAll() + // 所有类型的接口都放行 + .antMatchers(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray(new String[0])).permitAll() + // 所有请求都需要认证 + .anyRequest().authenticated() + .and().apply(securityConfigurerAdapter()); + } + + private TokenConfigurer securityConfigurerAdapter() { + return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheClean); + } + + private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) { + Map<String, Set<String>> anonymousUrls = new HashMap<>(8); + Set<String> get = new HashSet<>(); + Set<String> post = new HashSet<>(); + Set<String> put = new HashSet<>(); + Set<String> patch = new HashSet<>(); + Set<String> delete = new HashSet<>(); + Set<String> all = new HashSet<>(); + for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) { + HandlerMethod handlerMethod = infoEntry.getValue(); + AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class); + if (null != anonymousAccess) { + List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods()); + RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name()); + switch (Objects.requireNonNull(request)) { + case GET: + get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case POST: + post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case PUT: + put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case PATCH: + patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + case DELETE: + delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + default: + all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); + break; + } + } + } + anonymousUrls.put(RequestMethodEnum.GET.getType(), get); + anonymousUrls.put(RequestMethodEnum.POST.getType(), post); + anonymousUrls.put(RequestMethodEnum.PUT.getType(), put); + anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch); + anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete); + anonymousUrls.put(RequestMethodEnum.ALL.getType(), all); + return anonymousUrls; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCode.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCode.java new file mode 100644 index 0000000..02fbc23 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCode.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.config.bean; + +import lombok.Data; + +/** + * 登录验证码配置信息 + * + * @author liaojinlong + * 2020/6/10 18:53 + */ +@Data +public class LoginCode { + + /** + * 验证码配置 + */ + private LoginCodeEnum codeType; + /** + * 验证码有效期 分钟 + */ + private Long expiration = 2L; + /** + * 验证码内容长度 + */ + private int length = 2; + /** + * 验证码宽度 + */ + private int width = 111; + /** + * 验证码高度 + */ + private int height = 36; + /** + * 验证码字体 + */ + private String fontName; + /** + * 字体大小 + */ + private int fontSize = 25; + + public LoginCodeEnum getCodeType() { + return codeType; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCodeEnum.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCodeEnum.java new file mode 100644 index 0000000..d9fe369 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginCodeEnum.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.config.bean; + +/** + * 验证码配置枚举 + * + * @author: liaojinlong + * : 2020/6/10 17:40 + */ + +public enum LoginCodeEnum { + /** + * 算数 + */ + ARITHMETIC, + /** + * 中文 + */ + CHINESE, + /** + * 中文闪图 + */ + CHINESE_GIF, + /** + * 闪图 + */ + GIF, + SPEC +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginProperties.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginProperties.java new file mode 100644 index 0000000..f4b6754 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/LoginProperties.java @@ -0,0 +1,135 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version loginCode.length.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-loginCode.length.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.config.bean; + +import com.wf.captcha.*; +import com.wf.captcha.base.Captcha; +import lombok.Data; +import com.example.exception.BadConfigurationException; +import com.example.utils.StringUtils; + +import java.awt.*; +import java.util.Objects; + +/** + * 配置文件读取 + * + * @author liaojinlong + * loginCode.length0loginCode.length0/6/10 17:loginCode.length6 + */ +@Data +public class LoginProperties { + + /** + * 账号单用户 登录 + */ + private boolean singleLogin = false; + + private LoginCode loginCode; + + /** + * 用户登录信息缓存 + */ + private boolean cacheEnable; + + public boolean isSingleLogin() { + return singleLogin; + } + + public boolean isCacheEnable() { + return cacheEnable; + } + + /** + * 获取验证码生产类 + * + * @return / + */ + public Captcha getCaptcha() { + if (Objects.isNull(loginCode)) { + loginCode = new LoginCode(); + if (Objects.isNull(loginCode.getCodeType())) { + loginCode.setCodeType(LoginCodeEnum.ARITHMETIC); + } + } + return switchCaptcha(loginCode); + } + + /** + * 依据配置信息生产验证码 + * + * @param loginCode 验证码配置信息 + * @return / + */ + private Captcha switchCaptcha(LoginCode loginCode) { + Captcha captcha; + synchronized (this) { + switch (loginCode.getCodeType()) { + case ARITHMETIC: + // 算术类型 https://gitee.com/whvse/EasyCaptcha + captcha = new FixedArithmeticCaptcha(loginCode.getWidth(), loginCode.getHeight()); + // 几位数运算,默认是两位 + captcha.setLen(loginCode.getLength()); + break; + case CHINESE: + captcha = new ChineseCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + case CHINESE_GIF: + captcha = new ChineseGifCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + case GIF: + captcha = new GifCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + case SPEC: + captcha = new SpecCaptcha(loginCode.getWidth(), loginCode.getHeight()); + captcha.setLen(loginCode.getLength()); + break; + default: + throw new BadConfigurationException("验证码配置信息错误!正确配置查看 LoginCodeEnum "); + } + } + if(StringUtils.isNotBlank(loginCode.getFontName())){ + captcha.setFont(new Font(loginCode.getFontName(), Font.PLAIN, loginCode.getFontSize())); + } + return captcha; + } + + static class FixedArithmeticCaptcha extends ArithmeticCaptcha { + public FixedArithmeticCaptcha(int width, int height) { + super(width, height); + } + + @Override + protected char[] alphas() { + // 生成随机数字和运算符 + int n1 = num(1, 10), n2 = num(1, 10); + int opt = num(3); + + // 计算结果 + int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt]; + // 转换为字符运算符 + char optChar = "+-x".charAt(opt); + + this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2)); + this.chars = String.valueOf(res); + + return chars.toCharArray(); + } + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/SecurityProperties.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/SecurityProperties.java new file mode 100644 index 0000000..f341003 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/config/bean/SecurityProperties.java @@ -0,0 +1,72 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.config.bean; + +import lombok.Data; + +/** + * Jwt参数配置 + * + * + * 2019年11月28日 + */ +@Data +public class SecurityProperties { + + /** + * Request Headers : Authorization + */ + private String header; + + /** + * 令牌前缀,最后留个空格 Bearer + */ + private String tokenStartWith; + + /** + * 必须使用最少88位的Base64对该令牌进行编码 + */ + private String base64Secret; + + /** + * 令牌过期时间 此处单位/毫秒 + */ + private Long tokenValidityInSeconds; + + /** + * 在线用户 key,根据 key 查询 redis 中在线用户的数据 + */ + private String onlineKey; + + /** + * 验证码 key + */ + private String codeKey; + + /** + * token 续期检查 + */ + private Long detect; + + /** + * 续期时间 + */ + private Long renew; + + public String getTokenStartWith() { + return tokenStartWith + " "; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/AuthorizationController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/AuthorizationController.java new file mode 100644 index 0000000..7e2148b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/AuthorizationController.java @@ -0,0 +1,146 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.rest; + +import cn.hutool.core.util.IdUtil; +import com.wf.captcha.base.Captcha; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import com.example.annotation.rest.AnonymousDeleteMapping; +import com.example.annotation.rest.AnonymousGetMapping; +import com.example.annotation.rest.AnonymousPostMapping; +import com.example.config.RsaProperties; +import com.example.exception.BadRequestException; +import com.example.modules.security.config.bean.LoginCodeEnum; +import com.example.modules.security.config.bean.LoginProperties; +import com.example.modules.security.config.bean.SecurityProperties; +import com.example.modules.security.security.TokenProvider; +import com.example.modules.security.service.dto.AuthUserDto; +import com.example.modules.security.service.dto.JwtUserDto; +import com.example.modules.security.service.OnlineUserService; +import com.example.utils.RsaUtils; +import com.example.utils.RedisUtils; +import com.example.utils.SecurityUtils; +import com.example.utils.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * + * 2018-11-23 + * 授权、根据token获取用户详细信息 + */ +@Slf4j +@RestController +@RequestMapping("/auth") +@RequiredArgsConstructor +@Api(tags = "系统:系统授权接口") +public class AuthorizationController { + private final SecurityProperties properties; + private final RedisUtils redisUtils; + private final OnlineUserService onlineUserService; + private final TokenProvider tokenProvider; + private final AuthenticationManagerBuilder authenticationManagerBuilder; + @Resource + private LoginProperties loginProperties; + + @ApiOperation("登录授权") + @AnonymousPostMapping(value = "/login") + public ResponseEntity<Object> login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception { + // 密码解密 + String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword()); + //去除验证码功能 +/* // 查询验证码 + String code = (String) redisUtils.get(authUser.getUuid()); + // 清除验证码 + redisUtils.del(authUser.getUuid()); + if (StringUtils.isBlank(code)) { + throw new BadRequestException("验证码不存在或已过期"); + } + if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) { + throw new BadRequestException("验证码错误"); + }*/ + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken(authUser.getUsername(), password); + Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + // 生成令牌与第三方系统获取令牌方式 + // UserDetails userDetails = userDetailsService.loadUserByUsername(userInfo.getUsername()); + // Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + // SecurityContextHolder.getContext().setAuthentication(authentication); + String token = tokenProvider.createToken(authentication); + final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal(); + // 保存在线信息 + onlineUserService.save(jwtUserDto, token, request); + // 返回 token 与 用户信息 + Map<String, Object> authInfo = new HashMap<String, Object>(2) {{ + put("token", properties.getTokenStartWith() + token); + put("user", jwtUserDto); + }}; + if (loginProperties.isSingleLogin()) { + //踢掉之前已经登录的token + onlineUserService.checkLoginOnUser(authUser.getUsername(), token); + } + return ResponseEntity.ok(authInfo); + } + + @ApiOperation("获取用户信息") + @GetMapping(value = "/info") + public ResponseEntity<Object> getUserInfo() { + return ResponseEntity.ok(SecurityUtils.getCurrentUser()); + } + + @ApiOperation("获取验证码") + @AnonymousGetMapping(value = "/code") + public ResponseEntity<Object> getCode() { + // 获取运算的结果 + Captcha captcha = loginProperties.getCaptcha(); + String uuid = properties.getCodeKey() + IdUtil.simpleUUID(); + //当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型 + String captchaValue = captcha.text(); + if (captcha.getCharType() - 1 == LoginCodeEnum.ARITHMETIC.ordinal() && captchaValue.contains(".")) { + captchaValue = captchaValue.split("\\.")[0]; + } + // 保存 + redisUtils.set(uuid, captchaValue, loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES); + // 验证码信息 + Map<String, Object> imgResult = new HashMap<String, Object>(2) {{ + put("img", captcha.toBase64()); + put("uuid", uuid); + }}; + return ResponseEntity.ok(imgResult); + } + + @ApiOperation("退出登录") + @AnonymousDeleteMapping(value = "/logout") + public ResponseEntity<Object> logout(HttpServletRequest request) { + onlineUserService.logout(tokenProvider.getToken(request)); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/OnlineController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/OnlineController.java new file mode 100644 index 0000000..c4962a3 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/rest/OnlineController.java @@ -0,0 +1,68 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.rest; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import com.example.modules.security.service.OnlineUserService; +import com.example.utils.EncryptUtils; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** + * + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/auth/online") +@Api(tags = "系统:在线用户管理") +public class OnlineController { + + private final OnlineUserService onlineUserService; + + @ApiOperation("查询在线用户") + @GetMapping + @PreAuthorize("@el.check()") + public ResponseEntity<Object> queryOnlineUser(String filter, Pageable pageable){ + return new ResponseEntity<>(onlineUserService.getAll(filter, pageable),HttpStatus.OK); + } + + @ApiOperation("导出数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check()") + public void exportOnlineUser(HttpServletResponse response, String filter) throws IOException { + onlineUserService.download(onlineUserService.getAll(filter), response); + } + + @ApiOperation("踢出用户") + @DeleteMapping + @PreAuthorize("@el.check()") + public ResponseEntity<Object> deleteOnlineUser(@RequestBody Set<String> keys) throws Exception { + for (String key : keys) { + // 解密Key + key = EncryptUtils.desDecrypt(key); + onlineUserService.kickOut(key); + } + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAccessDeniedHandler.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAccessDeniedHandler.java new file mode 100644 index 0000000..c0b6f86 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAccessDeniedHandler.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.security; + +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * + */ +@Component +public class JwtAccessDeniedHandler implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { + //当用户在没有授权的情况下访问受保护的REST资源时,将调用此方法发送403 Forbidden响应 + response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage()); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAuthenticationEntryPoint.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..9fa256e --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/JwtAuthenticationEntryPoint.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.security; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * + */ +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException { + // 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应 + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage()); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenConfigurer.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenConfigurer.java new file mode 100644 index 0000000..2a1ad1c --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenConfigurer.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.security; + +import com.example.modules.security.config.bean.SecurityProperties; +import com.example.modules.security.service.OnlineUserService; +import com.example.modules.security.service.UserCacheClean; +import lombok.RequiredArgsConstructor; +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +/** + * @author / + */ +@RequiredArgsConstructor +public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { + + private final TokenProvider tokenProvider; + private final SecurityProperties properties; + private final OnlineUserService onlineUserService; + private final UserCacheClean userCacheClean; + + @Override + public void configure(HttpSecurity http) { + TokenFilter customFilter = new TokenFilter(tokenProvider, properties, onlineUserService, userCacheClean); + http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenFilter.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenFilter.java new file mode 100644 index 0000000..dc1369e --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenFilter.java @@ -0,0 +1,109 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.security; + +import cn.hutool.core.util.StrUtil; +import com.example.modules.security.config.bean.SecurityProperties; +import com.example.modules.security.service.OnlineUserService; +import com.example.modules.security.service.UserCacheClean; +import com.example.modules.security.service.dto.OnlineUserDto; +import io.jsonwebtoken.ExpiredJwtException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.GenericFilterBean; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.Objects; + +/** + * @author / + */ +public class TokenFilter extends GenericFilterBean { + private static final Logger log = LoggerFactory.getLogger(TokenFilter.class); + + + private final TokenProvider tokenProvider; + private final SecurityProperties properties; + private final OnlineUserService onlineUserService; + private final UserCacheClean userCacheClean; + + /** + * @param tokenProvider Token + * @param properties JWT + * @param onlineUserService 用户在线 + * @param userCacheClean 用户缓存清理工具 + */ + public TokenFilter(TokenProvider tokenProvider, SecurityProperties properties, OnlineUserService onlineUserService, UserCacheClean userCacheClean) { + this.properties = properties; + this.onlineUserService = onlineUserService; + this.tokenProvider = tokenProvider; + this.userCacheClean = userCacheClean; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + String token = resolveToken(httpServletRequest); + // 对于 Token 为空的不需要去查 Redis + if (StrUtil.isNotBlank(token)) { + OnlineUserDto onlineUserDto = null; + boolean cleanUserCache = false; + try { + onlineUserDto = onlineUserService.getOne(properties.getOnlineKey() + token); + } catch (ExpiredJwtException e) { + log.error(e.getMessage()); + cleanUserCache = true; + } finally { + if (cleanUserCache || Objects.isNull(onlineUserDto)) { + userCacheClean.cleanUserCache(String.valueOf(tokenProvider.getClaims(token).get(TokenProvider.AUTHORITIES_KEY))); + } + } + if (onlineUserDto != null && StringUtils.hasText(token)) { + Authentication authentication = tokenProvider.getAuthentication(token); + SecurityContextHolder.getContext().setAuthentication(authentication); + // Token 续期 + tokenProvider.checkRenewal(token); + } + } + filterChain.doFilter(servletRequest, servletResponse); + } + + /** + * 初步检测Token + * + * @param request / + * @return / + */ + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader(properties.getHeader()); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) { + // 去掉令牌前缀 + return bearerToken.replace(properties.getTokenStartWith(), ""); + } else { + log.debug("非法Token:{}", bearerToken); + } + return null; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenProvider.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenProvider.java new file mode 100644 index 0000000..dfe2134 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/security/TokenProvider.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.security; + +import cn.hutool.core.date.DateField; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import com.example.modules.security.config.bean.SecurityProperties; +import com.example.utils.RedisUtils; +import io.jsonwebtoken.*; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; +import java.security.Key; +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * @author / + */ +@Slf4j +@Component +public class TokenProvider implements InitializingBean { + + private final SecurityProperties properties; + private final RedisUtils redisUtils; + public static final String AUTHORITIES_KEY = "user"; + private JwtParser jwtParser; + private JwtBuilder jwtBuilder; + + public TokenProvider(SecurityProperties properties, RedisUtils redisUtils) { + this.properties = properties; + this.redisUtils = redisUtils; + } + + @Override + public void afterPropertiesSet() { + byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret()); + Key key = Keys.hmacShaKeyFor(keyBytes); + jwtParser = Jwts.parserBuilder() + .setSigningKey(key) + .build(); + jwtBuilder = Jwts.builder() + .signWith(key, SignatureAlgorithm.HS512); + } + + /** + * 创建Token 设置永不过期, + * Token 的时间有效性转到Redis 维护 + * + * @param authentication / + * @return / + */ + public String createToken(Authentication authentication) { + return jwtBuilder + // 加入ID确保生成的 Token 都不一致 + .setId(IdUtil.simpleUUID()) + .claim(AUTHORITIES_KEY, authentication.getName()) + .setSubject(authentication.getName()) + .compact(); + } + + /** + * 依据Token 获取鉴权信息 + * + * @param token / + * @return / + */ + Authentication getAuthentication(String token) { + Claims claims = getClaims(token); + User principal = new User(claims.getSubject(), "******", new ArrayList<>()); + return new UsernamePasswordAuthenticationToken(principal, token, new ArrayList<>()); + } + + public Claims getClaims(String token) { + return jwtParser + .parseClaimsJws(token) + .getBody(); + } + + /** + * @param token 需要检查的token + */ + public void checkRenewal(String token) { + // 判断是否续期token,计算token的过期时间 + long time = redisUtils.getExpire(properties.getOnlineKey() + token) * 1000; + Date expireDate = DateUtil.offset(new Date(), DateField.MILLISECOND, (int) time); + // 判断当前时间与过期时间的时间差 + long differ = expireDate.getTime() - System.currentTimeMillis(); + // 如果在续期检查的范围内,则续期 + if (differ <= properties.getDetect()) { + long renew = time + properties.getRenew(); + redisUtils.expire(properties.getOnlineKey() + token, renew, TimeUnit.MILLISECONDS); + } + } + + public String getToken(HttpServletRequest request) { + final String requestHeader = request.getHeader(properties.getHeader()); + if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) { + return requestHeader.substring(7); + } + return null; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/OnlineUserService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/OnlineUserService.java new file mode 100644 index 0000000..9cfda04 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/OnlineUserService.java @@ -0,0 +1,192 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.service; + +import com.example.modules.security.config.bean.SecurityProperties; +import com.example.utils.*; +import lombok.extern.slf4j.Slf4j; +import com.example.modules.security.service.dto.JwtUserDto; +import com.example.modules.security.service.dto.OnlineUserDto; +import com.example.utils.*; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** + * + * 2019年10月26日21:56:27 + */ +@Service +@Slf4j +public class OnlineUserService { + + private final SecurityProperties properties; + private final RedisUtils redisUtils; + + public OnlineUserService(SecurityProperties properties, RedisUtils redisUtils) { + this.properties = properties; + this.redisUtils = redisUtils; + } + + /** + * 保存在线用户信息 + * @param jwtUserDto / + * @param token / + * @param request / + */ + public void save(JwtUserDto jwtUserDto, String token, HttpServletRequest request){ + String dept = jwtUserDto.getUser().getDept().getName(); + String ip = StringUtils.getIp(request); + String browser = StringUtils.getBrowser(request); + String address = StringUtils.getCityInfo(ip); + OnlineUserDto onlineUserDto = null; + try { + onlineUserDto = new OnlineUserDto(jwtUserDto.getUsername(), jwtUserDto.getUser().getNickName(), dept, browser , ip, address, EncryptUtils.desEncrypt(token), new Date()); + } catch (Exception e) { + log.error(e.getMessage(),e); + } + redisUtils.set(properties.getOnlineKey() + token, onlineUserDto, properties.getTokenValidityInSeconds()/1000); + } + + /** + * 查询全部数据 + * @param filter / + * @param pageable / + * @return / + */ + public Map<String,Object> getAll(String filter, Pageable pageable){ + List<OnlineUserDto> onlineUserDtos = getAll(filter); + return PageUtil.toPage( + PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(), onlineUserDtos), + onlineUserDtos.size() + ); + } + + /** + * 查询全部数据,不分页 + * @param filter / + * @return / + */ + public List<OnlineUserDto> getAll(String filter){ + List<String> keys = redisUtils.scan(properties.getOnlineKey() + "*"); + Collections.reverse(keys); + List<OnlineUserDto> onlineUserDtos = new ArrayList<>(); + for (String key : keys) { + OnlineUserDto onlineUserDto = (OnlineUserDto) redisUtils.get(key); + if(StringUtils.isNotBlank(filter)){ + if(onlineUserDto.toString().contains(filter)){ + onlineUserDtos.add(onlineUserDto); + } + } else { + onlineUserDtos.add(onlineUserDto); + } + } + onlineUserDtos.sort((o1, o2) -> o2.getLoginTime().compareTo(o1.getLoginTime())); + return onlineUserDtos; + } + + /** + * 踢出用户 + * @param key / + */ + public void kickOut(String key){ + key = properties.getOnlineKey() + key; + redisUtils.del(key); + } + + /** + * 退出登录 + * @param token / + */ + public void logout(String token) { + String key = properties.getOnlineKey() + token; + redisUtils.del(key); + } + + /** + * 导出 + * @param all / + * @param response / + * @throws IOException / + */ + public void download(List<OnlineUserDto> all, HttpServletResponse response) throws IOException { + List<Map<String, Object>> list = new ArrayList<>(); + for (OnlineUserDto user : all) { + Map<String,Object> map = new LinkedHashMap<>(); + map.put("用户名", user.getUserName()); + map.put("部门", user.getDept()); + map.put("登录IP", user.getIp()); + map.put("登录地点", user.getAddress()); + map.put("浏览器", user.getBrowser()); + map.put("登录日期", user.getLoginTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + /** + * 查询用户 + * @param key / + * @return / + */ + public OnlineUserDto getOne(String key) { + return (OnlineUserDto)redisUtils.get(key); + } + + /** + * 检测用户是否在之前已经登录,已经登录踢下线 + * @param userName 用户名 + */ + public void checkLoginOnUser(String userName, String igoreToken){ + List<OnlineUserDto> onlineUserDtos = getAll(userName); + if(onlineUserDtos ==null || onlineUserDtos.isEmpty()){ + return; + } + for(OnlineUserDto onlineUserDto : onlineUserDtos){ + if(onlineUserDto.getUserName().equals(userName)){ + try { + String token =EncryptUtils.desDecrypt(onlineUserDto.getKey()); + if(StringUtils.isNotBlank(igoreToken)&&!igoreToken.equals(token)){ + this.kickOut(token); + }else if(StringUtils.isBlank(igoreToken)){ + this.kickOut(token); + } + } catch (Exception e) { + log.error("checkUser is error",e); + } + } + } + } + + /** + * 根据用户名强退用户 + * @param username / + */ + @Async + public void kickOutForUsername(String username) throws Exception { + List<OnlineUserDto> onlineUsers = getAll(username); + for (OnlineUserDto onlineUser : onlineUsers) { + if (onlineUser.getUserName().equals(username)) { + String token =EncryptUtils.desDecrypt(onlineUser.getKey()); + kickOut(token); + } + } + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheClean.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheClean.java new file mode 100644 index 0000000..aa1ef9c --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheClean.java @@ -0,0 +1,53 @@ +/* + * Copyright 2019-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.modules.security.service; + +import lombok.AllArgsConstructor; +import com.example.utils.StringUtils; +import org.springframework.stereotype.Component; + +/** + * @author: liaojinlong + * : 2020/6/11 18:01 + * @apiNote: 用于清理 用户登录信息缓存,为防止Spring循环依赖与安全考虑 ,单独构成工具类 + */ +@Component +@AllArgsConstructor +public class UserCacheClean { + + private final UserCacheManager userCacheManager; + + /** + * 清理特定用户缓存信息<br> + * 用户信息变更时 + * + * @param userName / + */ + public void cleanUserCache(String userName) { + if (StringUtils.isNotEmpty(userName)) { + userCacheManager.remove(userName); + } + } + + /** + * 清理所有用户的缓存信息<br> + * ,如发生角色授权信息变化,可以简便的全部失效缓存 + */ + public void cleanAll() { + userCacheManager.clear(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheManager.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheManager.java new file mode 100644 index 0000000..9c1f60b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserCacheManager.java @@ -0,0 +1,110 @@ +package com.example.modules.security.service; + +import lombok.extern.slf4j.Slf4j; +import com.example.modules.security.service.dto.JwtUserDto; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 用户缓存 + * + * @author TikiWong + * 2022/1/27 8:23 + **/ +@Slf4j +@Component +public class UserCacheManager { + + @Value("${user-cache.min-evictable-size}") + private int minEvictableSize; + @Value("${user-cache.min-evictable-interval}") + private long minEvictableInterval; + @Value("${user-cache.min-idle-time}") + private long minIdleTime; + + private final Map<String, Node> cache = new ConcurrentHashMap<>(); + private final AtomicBoolean expelLock = new AtomicBoolean(true); + private long nextMinEvictableTime = 0; + + public Future<JwtUserDto> putIfAbsent(String username, Future<JwtUserDto> ft) { + Node tryNode = new Node(ft); + Node node = cache.putIfAbsent(username, tryNode); + expel(); + return nodeToDate(node); + } + + /** + * 缓存回收 + * 为避免超过边界后回收热点数据设置了最小生存时间 + * 回收时会保留在最小生存时间内的数据 + **/ + public void expel() { + long now = System.currentTimeMillis(); + if (cache.size() < minEvictableSize || + now < nextMinEvictableTime || + !expelLock.compareAndSet(true, false)) { + return; + } + long oldestTime = now; + int evictedCount = 0; + try { + Iterator<Map.Entry<String, Node>> iterator = cache.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry<String, Node> entry = iterator.next(); + long nodeTime = entry.getValue().getTime(); + if (nodeTime + minIdleTime < now) { + iterator.remove(); + evictedCount++; + } + oldestTime = Math.min(oldestTime, nodeTime); + } + } finally { + this.nextMinEvictableTime = Math.max(now + minEvictableInterval, oldestTime); + expelLock.set(true); + log.info("回收掉【{}】条用户缓存, 剩余缓存数为【{}】,下次可回收时间为【{}】秒后", + evictedCount, + cache.size(), + (this.nextMinEvictableTime - now) / 1000); + } + } + + public Future<JwtUserDto> get(String username) { + return nodeToDate(cache.get(username)); + } + + public void clear() { + cache.clear(); + } + + public void remove(String username) { + cache.remove(username); + } + + private Future<JwtUserDto> nodeToDate(Node node) { + return node == null ? null : node.getData(); + } + + private static class Node { + private final Future<JwtUserDto> data; + private final long time; + + public Node(Future<JwtUserDto> data) { + this.data = data; + this.time = System.currentTimeMillis(); + } + + public Future<JwtUserDto> getData() { + return data; + } + + public long getTime() { + return time; + } + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserDetailsServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserDetailsServiceImpl.java new file mode 100644 index 0000000..8d368f2 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/UserDetailsServiceImpl.java @@ -0,0 +1,159 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.service; + +import com.example.modules.security.config.bean.LoginProperties; +import com.example.modules.system.service.DataService; +import com.example.modules.system.service.RoleService; +import com.example.modules.system.service.UserService; +import com.example.modules.system.service.dto.UserDto; +import lombok.RequiredArgsConstructor; +import com.example.exception.BadRequestException; +import com.example.exception.EntityNotFoundException; +import com.example.modules.security.service.dto.JwtUserDto; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * 2018-11-22 + */ +@RequiredArgsConstructor +@Service("userDetailsService") +public class UserDetailsServiceImpl implements UserDetailsService { + private final UserService userService; + private final RoleService roleService; + private final DataService dataService; + private final LoginProperties loginProperties; + + private final UserCacheManager USER_DTO_CACHE; + + public void setEnableCache(boolean enableCache) { + this.loginProperties.setCacheEnable(enableCache); + } + + public static ExecutorService executor = newThreadPool(); + + @Override + public JwtUserDto loadUserByUsername(String username) { + JwtUserDto jwtUserDto = null; + Future<JwtUserDto> future = USER_DTO_CACHE.get(username); + if (!loginProperties.isCacheEnable()) { + UserDto user; + try { + user = userService.findByName(username); + } catch (EntityNotFoundException e) { + // SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException + throw new UsernameNotFoundException(username, e); + } + if (user == null) { + throw new UsernameNotFoundException(""); + } else { + if (!user.getEnabled()) { + throw new BadRequestException("账号未激活!"); + } + jwtUserDto = new JwtUserDto( + user, + dataService.getDeptIds(user), + roleService.mapToGrantedAuthorities(user) + ); + } + return jwtUserDto; + } + + if (future == null) { + Callable<JwtUserDto> call = () -> getJwtBySearchDb(username); + FutureTask<JwtUserDto> ft = new FutureTask<>(call); + future = USER_DTO_CACHE.putIfAbsent(username, ft); + if (future == null) { + future = ft; + executor.submit(ft); + } + try { + return future.get(); + } catch (CancellationException e) { + USER_DTO_CACHE.remove(username); + System.out.println("error" + Thread.currentThread().getName()); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e.getMessage()); + } + } else { + try { + jwtUserDto = future.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e.getMessage()); + } + // 检查dataScope是否修改 + List<Long> dataScopes = jwtUserDto.getDataScopes(); + dataScopes.clear(); + dataScopes.addAll(dataService.getDeptIds(jwtUserDto.getUser())); + + } + return jwtUserDto; + + } + + private JwtUserDto getJwtBySearchDb(String username) { + UserDto user; + try { + user = userService.findByName(username); + } catch (EntityNotFoundException e) { + // SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException + throw new UsernameNotFoundException("", e); + } + if (user == null) { + throw new UsernameNotFoundException(""); + } else { + if (!user.getEnabled()) { + throw new BadRequestException("账号未激活!"); + } + return new JwtUserDto( + user, + dataService.getDeptIds(user), + roleService.mapToGrantedAuthorities(user) + ); + } + + } + + public static ExecutorService newThreadPool() { + ThreadFactory namedThreadFactory = new ThreadFactory() { + final AtomicInteger sequence = new AtomicInteger(1); + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r); + int seq = this.sequence.getAndIncrement(); + thread.setName("future-task-thread" + (seq > 1 ? "-" + seq : "")); + if (!thread.isDaemon()) { + thread.setDaemon(true); + } + + return thread; + } + }; + return new ThreadPoolExecutor(10, 200, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(1024), + namedThreadFactory, + new ThreadPoolExecutor.AbortPolicy()); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/AuthUserDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/AuthUserDto.java new file mode 100644 index 0000000..983d690 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/AuthUserDto.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.service.dto; + +import lombok.Getter; +import lombok.Setter; +import javax.validation.constraints.NotBlank; + +/** + * + * 2018-11-30 + */ +@Getter +@Setter +public class AuthUserDto { + + @NotBlank + private String username; + + @NotBlank + private String password; + + private String code; + + private String uuid = ""; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/JwtUserDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/JwtUserDto.java new file mode 100644 index 0000000..20e1bc6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/JwtUserDto.java @@ -0,0 +1,79 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.service.dto; + +import com.alibaba.fastjson.annotation.JSONField; +import com.example.modules.system.service.dto.UserDto; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + + +@Getter +@AllArgsConstructor +public class JwtUserDto implements UserDetails { + + private final UserDto user; + + private final List<Long> dataScopes; + + @JSONField(serialize = false) + private final List<GrantedAuthority> authorities; + + public Set<String> getRoles() { + return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()); + } + + @Override + @JSONField(serialize = false) + public String getPassword() { + return user.getPassword(); + } + + @Override + @JSONField(serialize = false) + public String getUsername() { + return user.getUsername(); + } + + @JSONField(serialize = false) + @Override + public boolean isAccountNonExpired() { + return true; + } + + @JSONField(serialize = false) + @Override + public boolean isAccountNonLocked() { + return true; + } + + @JSONField(serialize = false) + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + @JSONField(serialize = false) + public boolean isEnabled() { + return user.getEnabled(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/OnlineUserDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/OnlineUserDto.java new file mode 100644 index 0000000..77ba3bc --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/security/service/dto/OnlineUserDto.java @@ -0,0 +1,73 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.security.service.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.util.Date; + +/** + * 在线用户 + * + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OnlineUserDto { + + /** + * 用户名 + */ + private String userName; + + /** + * 昵称 + */ + private String nickName; + + /** + * 岗位 + */ + private String dept; + + /** + * 浏览器 + */ + private String browser; + + /** + * IP + */ + private String ip; + + /** + * 地址 + */ + private String address; + + /** + * token + */ + private String key; + + /** + * 登录时间 + */ + private Date loginTime; + + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DeptController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DeptController.java new file mode 100644 index 0000000..0bef112 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DeptController.java @@ -0,0 +1,117 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.controller; + +import cn.hutool.core.collection.CollectionUtil; +import com.example.modules.system.domain.Dept; +import com.example.modules.system.service.DeptService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import com.example.annotation.Log; +import com.example.exception.BadRequestException; +import com.example.modules.system.service.dto.DeptDto; +import com.example.modules.system.service.dto.DeptQueryCriteria; +import com.example.utils.PageUtil; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.util.*; + +/** +* +* 2019-03-25 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:部门管理") +@RequestMapping("/api/dept") +public class DeptController { + + private final DeptService deptService; + private static final String ENTITY_NAME = "dept"; + + @ApiOperation("导出部门数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('dept:list')") + public void exportDept(HttpServletResponse response, DeptQueryCriteria criteria) throws Exception { + deptService.download(deptService.queryAll(criteria, false), response); + } + + @ApiOperation("查询部门") + @GetMapping + @PreAuthorize("@el.check('user:list','dept:list')") + public ResponseEntity<Object> queryDept(DeptQueryCriteria criteria) throws Exception { + List<DeptDto> deptDtos = deptService.queryAll(criteria, true); + return new ResponseEntity<>(PageUtil.toPage(deptDtos, deptDtos.size()),HttpStatus.OK); + } + + @ApiOperation("查询部门:根据ID获取同级与上级数据") + @PostMapping("/superior") + @PreAuthorize("@el.check('user:list','dept:list')") + public ResponseEntity<Object> getDeptSuperior(@RequestBody List<Long> ids) { + Set<DeptDto> deptDtos = new LinkedHashSet<>(); + for (Long id : ids) { + DeptDto deptDto = deptService.findById(id); + List<DeptDto> depts = deptService.getSuperior(deptDto, new ArrayList<>()); + deptDtos.addAll(depts); + } + return new ResponseEntity<>(deptService.buildTree(new ArrayList<>(deptDtos)),HttpStatus.OK); + } + + @Log("新增部门") + @ApiOperation("新增部门") + @PostMapping + @PreAuthorize("@el.check('dept:add')") + public ResponseEntity<Object> createDept(@Validated @RequestBody Dept resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + deptService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改部门") + @ApiOperation("修改部门") + @PutMapping + @PreAuthorize("@el.check('dept:edit')") + public ResponseEntity<Object> updateDept(@Validated(Dept.Update.class) @RequestBody Dept resources){ + deptService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除部门") + @ApiOperation("删除部门") + @DeleteMapping + @PreAuthorize("@el.check('dept:del')") + public ResponseEntity<Object> deleteDept(@RequestBody Set<Long> ids){ + Set<DeptDto> deptDtos = new HashSet<>(); + for (Long id : ids) { + List<Dept> deptList = deptService.findByPid(id); + deptDtos.add(deptService.findById(id)); + if(CollectionUtil.isNotEmpty(deptList)){ + deptDtos = deptService.getDeleteDepts(deptList, deptDtos); + } + } + // 验证是否被角色或用户关联 + deptService.verification(deptDtos); + deptService.delete(deptDtos); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictController.java new file mode 100644 index 0000000..8f4dec7 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictController.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.controller; + +import com.example.modules.system.domain.Dict; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import com.example.annotation.Log; +import com.example.exception.BadRequestException; +import com.example.modules.system.service.DictService; +import com.example.modules.system.service.dto.DictQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** +* +* 2019-04-10 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:字典管理") +@RequestMapping("/api/dict") +public class DictController { + + private final DictService dictService; + private static final String ENTITY_NAME = "dict"; + + @ApiOperation("导出字典数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('dict:list')") + public void exportDict(HttpServletResponse response, DictQueryCriteria criteria) throws IOException { + dictService.download(dictService.queryAll(criteria), response); + } + + @ApiOperation("查询字典") + @GetMapping(value = "/all") + @PreAuthorize("@el.check('dict:list')") + public ResponseEntity<Object> queryAllDict(){ + return new ResponseEntity<>(dictService.queryAll(new DictQueryCriteria()),HttpStatus.OK); + } + + @ApiOperation("查询字典") + @GetMapping + @PreAuthorize("@el.check('dict:list')") + public ResponseEntity<Object> queryDict(DictQueryCriteria resources, Pageable pageable){ + return new ResponseEntity<>(dictService.queryAll(resources,pageable),HttpStatus.OK); + } + + @Log("新增字典") + @ApiOperation("新增字典") + @PostMapping + @PreAuthorize("@el.check('dict:add')") + public ResponseEntity<Object> createDict(@Validated @RequestBody Dict resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + dictService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改字典") + @ApiOperation("修改字典") + @PutMapping + @PreAuthorize("@el.check('dict:edit')") + public ResponseEntity<Object> updateDict(@Validated(Dict.Update.class) @RequestBody Dict resources){ + dictService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除字典") + @ApiOperation("删除字典") + @DeleteMapping + @PreAuthorize("@el.check('dict:del')") + public ResponseEntity<Object> deleteDict(@RequestBody Set<Long> ids){ + dictService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictDetailController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictDetailController.java new file mode 100644 index 0000000..e3c5891 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/DictDetailController.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.controller; + +import com.example.modules.system.domain.DictDetail; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import com.example.annotation.Log; +import com.example.exception.BadRequestException; +import com.example.modules.system.service.DictDetailService; +import com.example.modules.system.service.dto.DictDetailDto; +import com.example.modules.system.service.dto.DictDetailQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** +* +* 2019-04-10 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:字典详情管理") +@RequestMapping("/api/dictDetail") +public class DictDetailController { + + private final DictDetailService dictDetailService; + private static final String ENTITY_NAME = "dictDetail"; + + @ApiOperation("查询字典详情") + @GetMapping + public ResponseEntity<Object> queryDictDetail(DictDetailQueryCriteria criteria, + @PageableDefault(sort = {"dictSort"}, direction = Sort.Direction.ASC) Pageable pageable){ + return new ResponseEntity<>(dictDetailService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @ApiOperation("查询多个字典详情") + @GetMapping(value = "/map") + public ResponseEntity<Object> getDictDetailMaps(@RequestParam String dictName){ + String[] names = dictName.split("[,,]"); + Map<String, List<DictDetailDto>> dictMap = new HashMap<>(16); + for (String name : names) { + dictMap.put(name, dictDetailService.getDictByName(name)); + } + return new ResponseEntity<>(dictMap, HttpStatus.OK); + } + + @Log("新增字典详情") + @ApiOperation("新增字典详情") + @PostMapping + @PreAuthorize("@el.check('dict:add')") + public ResponseEntity<Object> createDictDetail(@Validated @RequestBody DictDetail resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + dictDetailService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改字典详情") + @ApiOperation("修改字典详情") + @PutMapping + @PreAuthorize("@el.check('dict:edit')") + public ResponseEntity<Object> updateDictDetail(@Validated(DictDetail.Update.class) @RequestBody DictDetail resources){ + dictDetailService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除字典详情") + @ApiOperation("删除字典详情") + @DeleteMapping(value = "/{id}") + @PreAuthorize("@el.check('dict:del')") + public ResponseEntity<Object> deleteDictDetail(@PathVariable Long id){ + dictDetailService.delete(id); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/JobController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/JobController.java new file mode 100644 index 0000000..6106f0d --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/JobController.java @@ -0,0 +1,94 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.controller; + +import com.example.modules.system.domain.Job; +import com.example.modules.system.service.JobService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import com.example.annotation.Log; +import com.example.exception.BadRequestException; +import com.example.modules.system.service.dto.JobQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Set; + +/** +* +* 2019-03-29 +*/ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:岗位管理") +@RequestMapping("/api/job") +public class JobController { + + private final JobService jobService; + private static final String ENTITY_NAME = "job"; + + @ApiOperation("导出岗位数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('job:list')") + public void exportJob(HttpServletResponse response, JobQueryCriteria criteria) throws IOException { + jobService.download(jobService.queryAll(criteria), response); + } + + @ApiOperation("查询岗位") + @GetMapping + @PreAuthorize("@el.check('job:list','user:list')") + public ResponseEntity<Object> queryJob(JobQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(jobService.queryAll(criteria, pageable),HttpStatus.OK); + } + + @Log("新增岗位") + @ApiOperation("新增岗位") + @PostMapping + @PreAuthorize("@el.check('job:add')") + public ResponseEntity<Object> createJob(@Validated @RequestBody Job resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + jobService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改岗位") + @ApiOperation("修改岗位") + @PutMapping + @PreAuthorize("@el.check('job:edit')") + public ResponseEntity<Object> updateJob(@Validated(Job.Update.class) @RequestBody Job resources){ + jobService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除岗位") + @ApiOperation("删除岗位") + @DeleteMapping + @PreAuthorize("@el.check('job:del')") + public ResponseEntity<Object> deleteJob(@RequestBody Set<Long> ids){ + // 验证是否被用户关联 + jobService.verification(ids); + jobService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/LimitController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/LimitController.java new file mode 100644 index 0000000..636ec91 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/LimitController.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.controller; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import com.example.annotation.Limit; +import com.example.annotation.rest.AnonymousGetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author / + * 接口限流测试类 + */ +@RestController +@RequestMapping("/api/limit") +@Api(tags = "系统:限流测试管理") +public class LimitController { + + private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(); + + /** + * 测试限流注解,下面配置说明该接口 60秒内最多只能访问 10次,保存到redis的键名为 limit_test, + */ + @AnonymousGetMapping + @ApiOperation("测试") + @Limit(key = "test", period = 60, count = 10, name = "testLimit", prefix = "limit") + public int testLimit() { + return ATOMIC_INTEGER.incrementAndGet(); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MenuController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MenuController.java new file mode 100644 index 0000000..26a2f1a --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MenuController.java @@ -0,0 +1,147 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.controller; + +import cn.hutool.core.collection.CollectionUtil; +import com.example.modules.system.domain.Menu; +import com.example.modules.system.service.MenuService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import com.example.annotation.Log; +import com.example.exception.BadRequestException; +import com.example.modules.system.service.dto.MenuDto; +import com.example.modules.system.service.dto.MenuQueryCriteria; +import com.example.modules.system.service.mapstruct.MenuMapper; +import com.example.utils.PageUtil; +import com.example.utils.SecurityUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.util.*; +import java.util.stream.Collectors; + +/** + * + * 2018-12-03 + */ + +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:菜单管理") +@RequestMapping("/api/menus") +public class MenuController { + + private final MenuService menuService; + private final MenuMapper menuMapper; + private static final String ENTITY_NAME = "menu"; + + @ApiOperation("导出菜单数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('menu:list')") + public void exportMenu(HttpServletResponse response, MenuQueryCriteria criteria) throws Exception { + menuService.download(menuService.queryAll(criteria, false), response); + } + + @GetMapping(value = "/build") + @ApiOperation("获取前端所需菜单") + public ResponseEntity<Object> buildMenus(){ + List<MenuDto> menuDtoList = menuService.findByUser(SecurityUtils.getCurrentUserId()); + List<MenuDto> menuDtos = menuService.buildTree(menuDtoList); + return new ResponseEntity<>(menuService.buildMenus(menuDtos),HttpStatus.OK); + } + + @ApiOperation("返回全部的菜单") + @GetMapping(value = "/lazy") + @PreAuthorize("@el.check('menu:list','roles:list')") + public ResponseEntity<Object> queryAllMenu(@RequestParam Long pid){ + return new ResponseEntity<>(menuService.getMenus(pid),HttpStatus.OK); + } + + @ApiOperation("根据菜单ID返回所有子节点ID,包含自身ID") + @GetMapping(value = "/child") + @PreAuthorize("@el.check('menu:list','roles:list')") + public ResponseEntity<Object> childMenu(@RequestParam Long id){ + Set<Menu> menuSet = new HashSet<>(); + List<MenuDto> menuList = menuService.getMenus(id); + menuSet.add(menuService.findOne(id)); + menuSet = menuService.getChildMenus(menuMapper.toEntity(menuList), menuSet); + Set<Long> ids = menuSet.stream().map(Menu::getId).collect(Collectors.toSet()); + return new ResponseEntity<>(ids,HttpStatus.OK); + } + + @GetMapping + @ApiOperation("查询菜单") + @PreAuthorize("@el.check('menu:list')") + public ResponseEntity<Object> queryMenu(MenuQueryCriteria criteria) throws Exception { + List<MenuDto> menuDtoList = menuService.queryAll(criteria, true); + return new ResponseEntity<>(PageUtil.toPage(menuDtoList, menuDtoList.size()),HttpStatus.OK); + } + + @ApiOperation("查询菜单:根据ID获取同级与上级数据") + @PostMapping("/superior") + @PreAuthorize("@el.check('menu:list')") + public ResponseEntity<Object> getMenuSuperior(@RequestBody List<Long> ids) { + Set<MenuDto> menuDtos = new LinkedHashSet<>(); + if(CollectionUtil.isNotEmpty(ids)){ + for (Long id : ids) { + MenuDto menuDto = menuService.findById(id); + menuDtos.addAll(menuService.getSuperior(menuDto, new ArrayList<>())); + } + return new ResponseEntity<>(menuService.buildTree(new ArrayList<>(menuDtos)),HttpStatus.OK); + } + return new ResponseEntity<>(menuService.getMenus(null),HttpStatus.OK); + } + + @Log("新增菜单") + @ApiOperation("新增菜单") + @PostMapping + @PreAuthorize("@el.check('menu:add')") + public ResponseEntity<Object> createMenu(@Validated @RequestBody Menu resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + menuService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改菜单") + @ApiOperation("修改菜单") + @PutMapping + @PreAuthorize("@el.check('menu:edit')") + public ResponseEntity<Object> updateMenu(@Validated(Menu.Update.class) @RequestBody Menu resources){ + menuService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除菜单") + @ApiOperation("删除菜单") + @DeleteMapping + @PreAuthorize("@el.check('menu:del')") + public ResponseEntity<Object> deleteMenu(@RequestBody Set<Long> ids){ + Set<Menu> menuSet = new HashSet<>(); + for (Long id : ids) { + List<MenuDto> menuList = menuService.getMenus(id); + menuSet.add(menuService.findOne(id)); + menuSet = menuService.getChildMenus(menuMapper.toEntity(menuList), menuSet); + } + menuService.delete(menuSet); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MonitorController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MonitorController.java new file mode 100644 index 0000000..bb7bf02 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/MonitorController.java @@ -0,0 +1,45 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.controller; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import com.example.modules.system.service.MonitorService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +/** + * + * 2020-05-02 + */ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统-服务监控管理") +@RequestMapping("/api/monitor") +public class MonitorController { + + private final MonitorService serverService; + + @GetMapping + @ApiOperation("查询服务监控") + @PreAuthorize("@el.check('monitor:list')") + public ResponseEntity<Object> queryMonitor(){ + return new ResponseEntity<>(serverService.getServers(),HttpStatus.OK); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/RoleController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/RoleController.java new file mode 100644 index 0000000..8f4fae8 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/RoleController.java @@ -0,0 +1,154 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.controller; + +import cn.hutool.core.lang.Dict; +import com.example.modules.system.domain.Role; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import com.example.annotation.Log; +import com.example.exception.BadRequestException; +import com.example.modules.system.service.RoleService; +import com.example.modules.system.service.dto.RoleDto; +import com.example.modules.system.service.dto.RoleQueryCriteria; +import com.example.modules.system.service.dto.RoleSmallDto; +import com.example.utils.SecurityUtils; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * + * 2018-12-03 + */ +@RestController +@RequiredArgsConstructor +@Api(tags = "系统:角色管理") +@RequestMapping("/api/roles") +public class RoleController { + + private final RoleService roleService; + + private static final String ENTITY_NAME = "role"; + + @ApiOperation("获取单个role") + @GetMapping(value = "/{id}") + @PreAuthorize("@el.check('roles:list')") + public ResponseEntity<Object> findRoleById(@PathVariable Long id){ + return new ResponseEntity<>(roleService.findById(id), HttpStatus.OK); + } + + @ApiOperation("导出角色数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('role:list')") + public void exportRole(HttpServletResponse response, RoleQueryCriteria criteria) throws IOException { + roleService.download(roleService.queryAll(criteria), response); + } + + @ApiOperation("返回全部的角色") + @GetMapping(value = "/all") + @PreAuthorize("@el.check('roles:list','user:add','user:edit')") + public ResponseEntity<Object> queryAllRole(){ + return new ResponseEntity<>(roleService.queryAll(),HttpStatus.OK); + } + + @ApiOperation("查询角色") + @GetMapping + @PreAuthorize("@el.check('roles:list')") + public ResponseEntity<Object> queryRole(RoleQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(roleService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @ApiOperation("获取用户级别") + @GetMapping(value = "/level") + public ResponseEntity<Object> getRoleLevel(){ + return new ResponseEntity<>(Dict.create().set("level", getLevels(null)),HttpStatus.OK); + } + + @Log("新增角色") + @ApiOperation("新增角色") + @PostMapping + @PreAuthorize("@el.check('roles:add')") + public ResponseEntity<Object> createRole(@Validated @RequestBody Role resources){ + if (resources.getId() != null) { + throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID"); + } + getLevels(resources.getLevel()); + roleService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改角色") + @ApiOperation("修改角色") + @PutMapping + @PreAuthorize("@el.check('roles:edit')") + public ResponseEntity<Object> updateRole(@Validated(Role.Update.class) @RequestBody Role resources){ + getLevels(resources.getLevel()); + roleService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("修改角色菜单") + @ApiOperation("修改角色菜单") + @PutMapping(value = "/menu") + @PreAuthorize("@el.check('roles:edit')") + public ResponseEntity<Object> updateRoleMenu(@RequestBody Role resources){ + RoleDto role = roleService.findById(resources.getId()); + getLevels(role.getLevel()); + roleService.updateMenu(resources,role); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除角色") + @ApiOperation("删除角色") + @DeleteMapping + @PreAuthorize("@el.check('roles:del')") + public ResponseEntity<Object> deleteRole(@RequestBody Set<Long> ids){ + for (Long id : ids) { + RoleDto role = roleService.findById(id); + getLevels(role.getLevel()); + } + // 验证是否被用户关联 + roleService.verification(ids); + roleService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + /** + * 获取用户的角色级别 + * @return / + */ + private int getLevels(Integer level){ + List<Integer> levels = roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList()); + int min = Collections.min(levels); + if(level != null){ + if(level < min){ + throw new BadRequestException("权限不足,你的角色级别:" + min + ",低于操作的角色级别:" + level); + } + } + return min; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/UserController.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/UserController.java new file mode 100644 index 0000000..393a878 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/controller/UserController.java @@ -0,0 +1,196 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.controller; + +import cn.hutool.core.collection.CollectionUtil; +import com.example.modules.system.domain.Dept; +import com.example.modules.system.domain.vo.UserPassVo; +import com.example.modules.system.service.DataService; +import com.example.modules.system.service.DeptService; +import com.example.modules.system.service.UserService; +import com.example.utils.PageUtil; +import com.example.utils.RsaUtils; +import com.example.utils.SecurityUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import com.example.annotation.Log; +import com.example.config.RsaProperties; +import com.example.modules.system.domain.User; +import com.example.exception.BadRequestException; +import com.example.modules.system.service.RoleService; +import com.example.modules.system.service.dto.RoleSmallDto; +import com.example.modules.system.service.dto.UserDto; +import com.example.modules.system.service.dto.UserQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + + +@Api(tags = "系统:用户管理") +@RestController +@RequestMapping("/api/users") +@RequiredArgsConstructor +public class UserController { + + private final PasswordEncoder passwordEncoder; + private final UserService userService; + private final DataService dataService; + private final DeptService deptService; + private final RoleService roleService; + + @ApiOperation("导出用户数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('user:list')") + public void exportUser(HttpServletResponse response, UserQueryCriteria criteria) throws IOException { + userService.download(userService.queryAll(criteria), response); + } + + @ApiOperation("查询用户") + @GetMapping + @PreAuthorize("@el.check('user:list')") + public ResponseEntity<Object> queryUser(UserQueryCriteria criteria, Pageable pageable){ + if (!ObjectUtils.isEmpty(criteria.getDeptId())) { + criteria.getDeptIds().add(criteria.getDeptId()); + // 先查找是否存在子节点 + List<Dept> data = deptService.findByPid(criteria.getDeptId()); + // 然后把子节点的ID都加入到集合中 + criteria.getDeptIds().addAll(deptService.getDeptChildren(data)); + } + // 数据权限 + List<Long> dataScopes = dataService.getDeptIds(userService.findByName(SecurityUtils.getCurrentUsername())); + // criteria.getDeptIds() 不为空并且数据权限不为空则取交集 + if (!CollectionUtils.isEmpty(criteria.getDeptIds()) && !CollectionUtils.isEmpty(dataScopes)){ + // 取交集 + criteria.getDeptIds().retainAll(dataScopes); + if(!CollectionUtil.isEmpty(criteria.getDeptIds())){ + return new ResponseEntity<>(userService.queryAll(criteria,pageable),HttpStatus.OK); + } + } else { + // 否则取并集 + criteria.getDeptIds().addAll(dataScopes); + return new ResponseEntity<>(userService.queryAll(criteria,pageable),HttpStatus.OK); + } + return new ResponseEntity<>(PageUtil.toPage(null,0),HttpStatus.OK); + } + + @Log("新增用户") + @ApiOperation("新增用户") + @PostMapping + @PreAuthorize("@el.check('user:add')") + public ResponseEntity<Object> createUser(@Validated @RequestBody User resources){ +// checkLevel(resources); + // 默认密码 123456 + resources.setPassword(passwordEncoder.encode("123456")); + userService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改用户") + @ApiOperation("修改用户") + @PutMapping + @PreAuthorize("@el.check('user:edit')") + public ResponseEntity<Object> updateUser(@Validated(User.Update.class) @RequestBody User resources) throws Exception { + checkLevel(resources); + userService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("修改用户:个人中心") + @ApiOperation("修改用户:个人中心") + @PutMapping(value = "center") + public ResponseEntity<Object> centerUser(@Validated(User.Update.class) @RequestBody User resources){ + if(!resources.getId().equals(SecurityUtils.getCurrentUserId())){ + throw new BadRequestException("不能修改他人资料"); + } + userService.updateCenter(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Log("删除用户") + @ApiOperation("删除用户") + @DeleteMapping + @PreAuthorize("@el.check('user:del')") + public ResponseEntity<Object> deleteUser(@RequestBody Set<Long> ids){ + for (Long id : ids) { + Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); + Integer optLevel = Collections.min(roleService.findByUsersId(id).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); + if (currentLevel > optLevel) { + throw new BadRequestException("角色权限不足,不能删除:" + userService.findById(id).getUsername()); + } + } + userService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @ApiOperation("修改密码") + @PostMapping(value = "/updatePass") + public ResponseEntity<Object> updateUserPass(@RequestBody UserPassVo passVo) throws Exception { + String oldPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getOldPass()); + String newPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getNewPass()); + UserDto user = userService.findByName(SecurityUtils.getCurrentUsername()); + if(!passwordEncoder.matches(oldPass, user.getPassword())){ + throw new BadRequestException("修改失败,旧密码错误"); + } + if(passwordEncoder.matches(newPass, user.getPassword())){ + throw new BadRequestException("新密码不能与旧密码相同"); + } + userService.updatePass(user.getUsername(),passwordEncoder.encode(newPass)); + return new ResponseEntity<>(HttpStatus.OK); + } + + @ApiOperation("修改头像") + @PostMapping(value = "/updateAvatar") + public ResponseEntity<Object> updateUserAvatar(@RequestParam MultipartFile avatar){ + return new ResponseEntity<>(userService.updateAvatar(avatar), HttpStatus.OK); + } + + @Log("修改邮箱") + @ApiOperation("修改邮箱") + @PostMapping(value = "/updateEmail/{code}") + public ResponseEntity<Object> updateUserEmail(@PathVariable String code,@RequestBody User user) throws Exception { + String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,user.getPassword()); + UserDto userDto = userService.findByName(SecurityUtils.getCurrentUsername()); + if(!passwordEncoder.matches(password, userDto.getPassword())){ + throw new BadRequestException("密码错误"); + } + userService.updateEmail(userDto.getUsername(),user.getEmail()); + return new ResponseEntity<>(HttpStatus.OK); + } + + /** + * 如果当前用户的角色级别低于创建用户的角色级别,则抛出权限不足的错误 + * @param resources / + */ + private void checkLevel(User resources) { + Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); + Integer optLevel = roleService.findByRoles(resources.getRoles()); + if (currentLevel > optLevel) { + throw new BadRequestException("角色权限不足"); + } + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dept.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dept.java new file mode 100644 index 0000000..4ef6ac1 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dept.java @@ -0,0 +1,86 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.domain; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** +* +* 2019-03-25 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_dept") +public class Dept extends BaseEntity implements Serializable { + + @Id + @Column(name = "dept_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JSONField(serialize = false) + @ManyToMany(mappedBy = "depts") + @ApiModelProperty(value = "角色") + private Set<Role> roles; + + @ApiModelProperty(value = "排序") + private Integer deptSort; + + @NotBlank + @ApiModelProperty(value = "部门名称") + private String name; + + @NotNull + @ApiModelProperty(value = "是否启用") + private Boolean enabled; + + @ApiModelProperty(value = "上级部门") + private Long pid; + + @ApiModelProperty(value = "子节点数目", hidden = true) + private Integer subCount = 0; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Dept dept = (Dept) o; + return Objects.equals(id, dept.id) && + Objects.equals(name, dept.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dict.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dict.java new file mode 100644 index 0000000..de65392 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Dict.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +/** +* +* 2019-04-10 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_dict") +public class Dict extends BaseEntity implements Serializable { + + @Id + @Column(name = "dict_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToMany(mappedBy = "dict",cascade={CascadeType.PERSIST,CascadeType.REMOVE}) + private List<DictDetail> dictDetails; + + @NotBlank + @ApiModelProperty(value = "名称") + private String name; + + @ApiModelProperty(value = "描述") + private String description; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/DictDetail.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/DictDetail.java new file mode 100644 index 0000000..538743e --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/DictDetail.java @@ -0,0 +1,56 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** +* +* 2019-04-10 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_dict_detail") +public class DictDetail extends BaseEntity implements Serializable { + + @Id + @Column(name = "detail_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JoinColumn(name = "dict_id") + @ManyToOne(fetch=FetchType.LAZY) + @ApiModelProperty(value = "字典", hidden = true) + private Dict dict; + + @ApiModelProperty(value = "字典标签") + private String label; + + @ApiModelProperty(value = "字典值") + private String value; + + @ApiModelProperty(value = "排序") + private Integer dictSort = 999; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Job.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Job.java new file mode 100644 index 0000000..f3f47b3 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Job.java @@ -0,0 +1,73 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; + +/** +* +* 2019-03-29 +*/ +@Entity +@Getter +@Setter +@Table(name="sys_job") +public class Job extends BaseEntity implements Serializable { + + @Id + @Column(name = "job_id") + @NotNull(groups = Update.class) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @ApiModelProperty(value = "岗位名称") + private String name; + + @NotNull + @ApiModelProperty(value = "岗位排序") + private Long jobSort; + + @NotNull + @ApiModelProperty(value = "是否启用") + private Boolean enabled; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Job job = (Job) o; + return Objects.equals(id, job.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Menu.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Menu.java new file mode 100644 index 0000000..0989055 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Menu.java @@ -0,0 +1,110 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.domain; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseEntity; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** + * + * 2018-12-17 + */ +@Entity +@Getter +@Setter +@Table(name = "sys_menu") +public class Menu extends BaseEntity implements Serializable { + + @Id + @Column(name = "menu_id") + @NotNull(groups = {Update.class}) + @ApiModelProperty(value = "ID", hidden = true) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JSONField(serialize = false) + @ManyToMany(mappedBy = "menus") + @ApiModelProperty(value = "菜单角色") + private Set<Role> roles; + + @ApiModelProperty(value = "菜单标题") + private String title; + + @Column(name = "name") + @ApiModelProperty(value = "菜单组件名称") + private String componentName; + + @ApiModelProperty(value = "排序") + private Integer menuSort = 999; + + @ApiModelProperty(value = "组件路径") + private String component; + + @ApiModelProperty(value = "路由地址") + private String path; + + @ApiModelProperty(value = "菜单类型,目录、菜单、按钮") + private Integer type; + + @ApiModelProperty(value = "权限标识") + private String permission; + + @ApiModelProperty(value = "菜单图标") + private String icon; + + @Column(columnDefinition = "bit(1) default 0") + @ApiModelProperty(value = "缓存") + private Boolean cache; + + @Column(columnDefinition = "bit(1) default 0") + @ApiModelProperty(value = "是否隐藏") + private Boolean hidden; + + @ApiModelProperty(value = "上级菜单") + private Long pid; + + @ApiModelProperty(value = "子节点数目", hidden = true) + private Integer subCount = 0; + + @ApiModelProperty(value = "外链菜单") + private Boolean iFrame; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Menu menu = (Menu) o; + return Objects.equals(id, menu.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Role.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Role.java new file mode 100644 index 0000000..b600f46 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/Role.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.domain; + +import com.alibaba.fastjson.annotation.JSONField; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseEntity; +import com.example.utils.enums.DataScopeEnum; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + +/** + * 角色 + * + * 2018-11-22 + */ +@Getter +@Setter +@Entity +@Table(name = "sys_role") +public class Role extends BaseEntity implements Serializable { + + @Id + @Column(name = "role_id") + @NotNull(groups = {Update.class}) + @GeneratedValue(strategy = GenerationType.IDENTITY) + @ApiModelProperty(value = "ID", hidden = true) + private Long id; + + @JSONField(serialize = false) + @ManyToMany(mappedBy = "roles") + @ApiModelProperty(value = "用户", hidden = true) + private Set<User> users; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "sys_roles_menus", + joinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}, + inverseJoinColumns = {@JoinColumn(name = "menu_id",referencedColumnName = "menu_id")}) + @ApiModelProperty(value = "菜单", hidden = true) + private Set<Menu> menus; + + @ManyToMany + @JoinTable(name = "sys_roles_depts", + joinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}, + inverseJoinColumns = {@JoinColumn(name = "dept_id",referencedColumnName = "dept_id")}) + @ApiModelProperty(value = "部门", hidden = true) + private Set<Dept> depts; + + @NotBlank + @ApiModelProperty(value = "名称", hidden = true) + private String name; + + @ApiModelProperty(value = "数据权限,全部 、 本级 、 自定义") + private String dataScope = DataScopeEnum.THIS_LEVEL.getValue(); + + @Column(name = "level") + @ApiModelProperty(value = "级别,数值越小,级别越大") + private Integer level = 3; + + @ApiModelProperty(value = "描述") + private String description; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Role role = (Role) o; + return Objects.equals(id, role.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/User.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/User.java new file mode 100644 index 0000000..fcbba83 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/User.java @@ -0,0 +1,125 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseEntity; +import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Date; +import java.util.Objects; +import java.util.Set; + +/** + * + * 2018-11-22 + */ +@Entity +@Getter +@Setter +@Table(name="sys_user") +public class User extends BaseEntity implements Serializable { + + @Id + @Column(name = "user_id") + @NotNull(groups = Update.class) + @GeneratedValue(strategy = GenerationType.IDENTITY) + @ApiModelProperty(value = "ID", hidden = true) + private Long id; + + @ManyToMany(fetch = FetchType.EAGER) + @ApiModelProperty(value = "用户角色") + @JoinTable(name = "sys_users_roles", + joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")}, + inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}) + private Set<Role> roles; + + @ManyToMany(fetch = FetchType.EAGER) + @ApiModelProperty(value = "用户岗位") + @JoinTable(name = "sys_users_jobs", + joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")}, + inverseJoinColumns = {@JoinColumn(name = "job_id",referencedColumnName = "job_id")}) + private Set<Job> jobs; + + @OneToOne + @JoinColumn(name = "dept_id") + @ApiModelProperty(value = "用户部门") + private Dept dept; + + @NotBlank + @Column(unique = true) + @ApiModelProperty(value = "用户名称") + private String username; + + @NotBlank + @ApiModelProperty(value = "用户昵称") + private String nickName; + + @Email + @NotBlank + @ApiModelProperty(value = "邮箱") + private String email; + + @NotBlank + @ApiModelProperty(value = "电话号码") + private String phone; + + @ApiModelProperty(value = "用户性别") + private String gender; + + @ApiModelProperty(value = "头像真实名称",hidden = true) + private String avatarName; + + @ApiModelProperty(value = "头像存储的路径", hidden = true) + private String avatarPath; + + @ApiModelProperty(value = "密码") + private String password; + + @NotNull + @ApiModelProperty(value = "是否启用") + private Boolean enabled; + + @ApiModelProperty(value = "是否为admin账号", hidden = true) + private Boolean isAdmin = false; + + @Column(name = "pwd_reset_time") + @ApiModelProperty(value = "最后修改密码的时间", hidden = true) + private Date pwdResetTime; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + User user = (User) o; + return Objects.equals(id, user.id) && + Objects.equals(username, user.username); + } + + @Override + public int hashCode() { + return Objects.hash(id, username); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuMetaVo.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuMetaVo.java new file mode 100644 index 0000000..68944cc --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuMetaVo.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import java.io.Serializable; + +/** + * + * 2018-12-20 + */ +@Data +@AllArgsConstructor +public class MenuMetaVo implements Serializable { + + private String title; + + private String icon; + + private Boolean noCache; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuVo.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuVo.java new file mode 100644 index 0000000..71c6161 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/MenuVo.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; +import java.io.Serializable; +import java.util.List; + +/** + * 构建前端路由时用到 + * + * 2018-12-20 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class MenuVo implements Serializable { + + private String name; + + private String path; + + private Boolean hidden; + + private String redirect; + + private String component; + + private Boolean alwaysShow; + + private MenuMetaVo meta; + + private List<MenuVo> children; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/UserPassVo.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/UserPassVo.java new file mode 100644 index 0000000..66869b2 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/domain/vo/UserPassVo.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.domain.vo; + +import lombok.Data; + +/** + * 修改密码的 Vo 类 + * + * 2019年7月11日13:59:49 + */ +@Data +public class UserPassVo { + + private String oldPass; + + private String newPass; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DeptRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DeptRepository.java new file mode 100644 index 0000000..5952659 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DeptRepository.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.repository; + +import com.example.modules.system.domain.Dept; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import java.util.List; +import java.util.Set; + +/** +* +* 2019-03-25 +*/ +public interface DeptRepository extends JpaRepository<Dept, Long>, JpaSpecificationExecutor<Dept> { + + /** + * 根据 PID 查询 + * @param id pid + * @return / + */ + List<Dept> findByPid(Long id); + + /** + * 获取顶级部门 + * @return / + */ + List<Dept> findByPidIsNull(); + + /** + * 根据角色ID 查询 + * @param roleId 角色ID + * @return / + */ + @Query(value = "select d.* from sys_dept d, sys_roles_depts r where " + + "d.dept_id = r.dept_id and r.role_id = ?1", nativeQuery = true) + Set<Dept> findByRoleId(Long roleId); + + /** + * 判断是否存在子节点 + * @param pid / + * @return / + */ + int countByPid(Long pid); + + /** + * 根据ID更新sub_count + * @param count / + * @param id / + */ + @Modifying + @Query(value = " update sys_dept set sub_count = ?1 where dept_id = ?2 ",nativeQuery = true) + void updateSubCntById(Integer count, Long id); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictDetailRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictDetailRepository.java new file mode 100644 index 0000000..315be98 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictDetailRepository.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.repository; + +import com.example.modules.system.domain.DictDetail; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** +* +* 2019-04-10 +*/ +public interface DictDetailRepository extends JpaRepository<DictDetail, Long>, JpaSpecificationExecutor<DictDetail> { + + /** + * 根据字典名称查询 + * @param name / + * @return / + */ + List<DictDetail> findByDictName(String name); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictRepository.java new file mode 100644 index 0000000..c2d1a49 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/DictRepository.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.repository; + +import com.example.modules.system.domain.Dict; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Set; + +/** +* +* 2019-04-10 +*/ +public interface DictRepository extends JpaRepository<Dict, Long>, JpaSpecificationExecutor<Dict> { + + /** + * 删除 + * @param ids / + */ + void deleteByIdIn(Set<Long> ids); + + /** + * 查询 + * @param ids / + * @return / + */ + List<Dict> findByIdIn(Set<Long> ids); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/JobRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/JobRepository.java new file mode 100644 index 0000000..d804309 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/JobRepository.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.repository; + +import com.example.modules.system.domain.Job; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.Set; + +/** +* +* 2019-03-29 +*/ +public interface JobRepository extends JpaRepository<Job, Long>, JpaSpecificationExecutor<Job> { + + /** + * 根据名称查询 + * @param name 名称 + * @return / + */ + Job findByName(String name); + + /** + * 根据Id删除 + * @param ids / + */ + void deleteAllByIdIn(Set<Long> ids); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/MenuRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/MenuRepository.java new file mode 100644 index 0000000..ac1e524 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/MenuRepository.java @@ -0,0 +1,85 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.repository; + +import com.example.modules.system.domain.Menu; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * + * 2018-12-17 + */ +public interface MenuRepository extends JpaRepository<Menu, Long>, JpaSpecificationExecutor<Menu> { + + /** + * 根据菜单标题查询 + * @param title 菜单标题 + * @return / + */ + Menu findByTitle(String title); + + /** + * 根据组件名称查询 + * @param name 组件名称 + * @return / + */ + Menu findByComponentName(String name); + + /** + * 根据菜单的 PID 查询 + * @param pid / + * @return / + */ + List<Menu> findByPid(long pid); + + /** + * 查询顶级菜单 + * @return / + */ + List<Menu> findByPidIsNull(); + + /** + * 根据角色ID与菜单类型查询菜单 + * @param roleIds roleIDs + * @param type 类型 + * @return / + */ + @Query(value = "SELECT m.* FROM sys_menu m, sys_roles_menus r WHERE " + + "m.menu_id = r.menu_id AND r.role_id IN ?1 AND type != ?2 order by m.menu_sort asc",nativeQuery = true) + LinkedHashSet<Menu> findByRoleIdsAndTypeNot(Set<Long> roleIds, int type); + + /** + * 获取节点数量 + * @param id / + * @return / + */ + int countByPid(Long id); + + /** + * 更新节点数目 + * @param count / + * @param menuId / + */ + @Modifying + @Query(value = " update sys_menu set sub_count = ?1 where menu_id = ?2 ",nativeQuery = true) + void updateSubCntById(int count, Long menuId); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/RoleRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/RoleRepository.java new file mode 100644 index 0000000..dd6e48b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/RoleRepository.java @@ -0,0 +1,80 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.repository; + +import com.example.modules.system.domain.Role; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; +import java.util.Set; + +/** + * + * 2018-12-03 + */ +public interface RoleRepository extends JpaRepository<Role, Long>, JpaSpecificationExecutor<Role> { + + /** + * 根据名称查询 + * @param name / + * @return / + */ + Role findByName(String name); + + /** + * 删除多个角色 + * @param ids / + */ + void deleteAllByIdIn(Set<Long> ids); + + /** + * 根据用户ID查询 + * @param id 用户ID + * @return / + */ + @Query(value = "SELECT r.* FROM sys_role r, sys_users_roles u WHERE " + + "r.role_id = u.role_id AND u.user_id = ?1",nativeQuery = true) + Set<Role> findByUserId(Long id); + + /** + * 解绑角色菜单 + * @param id 菜单ID + */ + @Modifying + @Query(value = "delete from sys_roles_menus where menu_id = ?1",nativeQuery = true) + void untiedMenu(Long id); + + /** + * 根据部门查询 + * @param deptIds / + * @return / + */ + @Query(value = "select count(1) from sys_role r, sys_roles_depts d where " + + "r.role_id = d.role_id and d.dept_id in ?1",nativeQuery = true) + int countByDepts(Set<Long> deptIds); + + /** + * 根据菜单Id查询 + * @param menuIds / + * @return / + */ + @Query(value = "SELECT r.* FROM sys_role r, sys_roles_menus m WHERE " + + "r.role_id = m.role_id AND m.menu_id in ?1",nativeQuery = true) + List<Role> findInMenuId(List<Long> menuIds); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/UserRepository.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/UserRepository.java new file mode 100644 index 0000000..620b247 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/repository/UserRepository.java @@ -0,0 +1,130 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.repository; + +import com.example.modules.system.domain.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import java.util.Date; +import java.util.List; +import java.util.Set; + +/** + * + * 2018-11-22 + */ +public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { + + /** + * 根据用户名查询 + * @param username 用户名 + * @return / + */ + User findByUsername(String username); + + /** + * 根据邮箱查询 + * @param email 邮箱 + * @return / + */ + User findByEmail(String email); + + /** + * 根据手机号查询 + * @param phone 手机号 + * @return / + */ + User findByPhone(String phone); + + /** + * 修改密码 + * @param username 用户名 + * @param pass 密码 + * @param lastPasswordResetTime / + */ + @Modifying + @Query(value = "update sys_user set password = ?2 , pwd_reset_time = ?3 where username = ?1",nativeQuery = true) + void updatePass(String username, String pass, Date lastPasswordResetTime); + + /** + * 修改邮箱 + * @param username 用户名 + * @param email 邮箱 + */ + @Modifying + @Query(value = "update sys_user set email = ?2 where username = ?1",nativeQuery = true) + void updateEmail(String username, String email); + + /** + * 根据角色查询用户 + * @param roleId / + * @return / + */ + @Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r WHERE" + + " u.user_id = r.user_id AND r.role_id = ?1", nativeQuery = true) + List<User> findByRoleId(Long roleId); + + /** + * 根据角色中的部门查询 + * @param deptId / + * @return / + */ + @Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r, sys_roles_depts d WHERE " + + "u.user_id = r.user_id AND r.role_id = d.role_id AND d.dept_id = ?1 group by u.user_id", nativeQuery = true) + List<User> findByRoleDeptId(Long deptId); + + /** + * 根据菜单查询 + * @param id 菜单ID + * @return / + */ + @Query(value = "SELECT u.* FROM sys_user u, sys_users_roles ur, sys_roles_menus rm WHERE\n" + + "u.user_id = ur.user_id AND ur.role_id = rm.role_id AND rm.menu_id = ?1 group by u.user_id", nativeQuery = true) + List<User> findByMenuId(Long id); + + /** + * 根据Id删除 + * @param ids / + */ + void deleteAllByIdIn(Set<Long> ids); + + /** + * 根据岗位查询 + * @param ids / + * @return / + */ + @Query(value = "SELECT count(1) FROM sys_user u, sys_users_jobs j WHERE u.user_id = j.user_id AND j.job_id IN ?1", nativeQuery = true) + int countByJobs(Set<Long> ids); + + /** + * 根据部门查询 + * @param deptIds / + * @return / + */ + @Query(value = "SELECT count(1) FROM sys_user u WHERE u.dept_id IN ?1", nativeQuery = true) + int countByDepts(Set<Long> deptIds); + + /** + * 根据角色查询 + * @param ids / + * @return / + */ + @Query(value = "SELECT count(1) FROM sys_user u, sys_users_roles r WHERE " + + "u.user_id = r.user_id AND r.role_id in ?1", nativeQuery = true) + int countByRoles(Set<Long> ids); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DataService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DataService.java new file mode 100644 index 0000000..de01bd9 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DataService.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service; + +import com.example.modules.system.service.dto.UserDto; +import java.util.List; + +/** + * 数据权限服务类 + * + * 2020-05-07 + */ +public interface DataService { + + /** + * 获取数据权限 + * @param user / + * @return / + */ + List<Long> getDeptIds(UserDto user); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DeptService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DeptService.java new file mode 100644 index 0000000..24f6138 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DeptService.java @@ -0,0 +1,124 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service; + +import com.example.modules.system.domain.Dept; +import com.example.modules.system.service.dto.DeptDto; +import com.example.modules.system.service.dto.DeptQueryCriteria; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** +* +* 2019-03-25 +*/ +public interface DeptService { + + /** + * 查询所有数据 + * @param criteria 条件 + * @param isQuery / + * @throws Exception / + * @return / + */ + List<DeptDto> queryAll(DeptQueryCriteria criteria, Boolean isQuery) throws Exception; + + /** + * 根据ID查询 + * @param id / + * @return / + */ + DeptDto findById(Long id); + + /** + * 创建 + * @param resources / + */ + void create(Dept resources); + + /** + * 编辑 + * @param resources / + */ + void update(Dept resources); + + /** + * 删除 + * @param deptDtos / + * + */ + void delete(Set<DeptDto> deptDtos); + + /** + * 根据PID查询 + * @param pid / + * @return / + */ + List<Dept> findByPid(long pid); + + /** + * 根据角色ID查询 + * @param id / + * @return / + */ + Set<Dept> findByRoleId(Long id); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List<DeptDto> queryAll, HttpServletResponse response) throws IOException; + + /** + * 获取待删除的部门 + * @param deptList / + * @param deptDtos / + * @return / + */ + Set<DeptDto> getDeleteDepts(List<Dept> deptList, Set<DeptDto> deptDtos); + + /** + * 根据ID获取同级与上级数据 + * @param deptDto / + * @param depts / + * @return / + */ + List<DeptDto> getSuperior(DeptDto deptDto, List<Dept> depts); + + /** + * 构建树形数据 + * @param deptDtos / + * @return / + */ + Object buildTree(List<DeptDto> deptDtos); + + /** + * 获取 + * @param deptList + * @return + */ + List<Long> getDeptChildren(List<Dept> deptList); + + /** + * 验证是否被角色或用户关联 + * @param deptDtos / + */ + void verification(Set<DeptDto> deptDtos); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictDetailService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictDetailService.java new file mode 100644 index 0000000..57e5a7f --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictDetailService.java @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service; + +import com.example.modules.system.domain.DictDetail; +import com.example.modules.system.service.dto.DictDetailDto; +import com.example.modules.system.service.dto.DictDetailQueryCriteria; +import org.springframework.data.domain.Pageable; +import java.util.List; +import java.util.Map; + +/** +* +* 2019-04-10 +*/ +public interface DictDetailService { + + /** + * 创建 + * @param resources / + */ + void create(DictDetail resources); + + /** + * 编辑 + * @param resources / + */ + void update(DictDetail resources); + + /** + * 删除 + * @param id / + */ + void delete(Long id); + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Map<String,Object> queryAll(DictDetailQueryCriteria criteria, Pageable pageable); + + /** + * 根据字典名称获取字典详情 + * @param name 字典名称 + * @return / + */ + List<DictDetailDto> getDictByName(String name); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictService.java new file mode 100644 index 0000000..8cf7e9c --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/DictService.java @@ -0,0 +1,75 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service; + +import com.example.modules.system.domain.Dict; +import com.example.modules.system.service.dto.DictDto; +import com.example.modules.system.service.dto.DictQueryCriteria; +import org.springframework.data.domain.Pageable; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** +* +* 2019-04-10 +*/ +public interface DictService { + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Map<String,Object> queryAll(DictQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param dict / + * @return / + */ + List<DictDto> queryAll(DictQueryCriteria dict); + + /** + * 创建 + * @param resources / + * @return / + */ + void create(Dict resources); + + /** + * 编辑 + * @param resources / + */ + void update(Dict resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set<Long> ids); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List<DictDto> queryAll, HttpServletResponse response) throws IOException; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/JobService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/JobService.java new file mode 100644 index 0000000..2fc99b6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/JobService.java @@ -0,0 +1,88 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service; + +import com.example.modules.system.domain.Job; +import com.example.modules.system.service.dto.JobDto; +import com.example.modules.system.service.dto.JobQueryCriteria; +import org.springframework.data.domain.Pageable; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** +* +* 2019-03-29 +*/ +public interface JobService { + + /** + * 根据ID查询 + * @param id / + * @return / + */ + JobDto findById(Long id); + + /** + * 创建 + * @param resources / + * @return / + */ + void create(Job resources); + + /** + * 编辑 + * @param resources / + */ + void update(Job resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set<Long> ids); + + /** + * 分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Map<String,Object> queryAll(JobQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部数据 + * @param criteria / + * @return / + */ + List<JobDto> queryAll(JobQueryCriteria criteria); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List<JobDto> queryAll, HttpServletResponse response) throws IOException; + + /** + * 验证是否被用户关联 + * @param ids / + */ + void verification(Set<Long> ids); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MenuService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MenuService.java new file mode 100644 index 0000000..4706705 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MenuService.java @@ -0,0 +1,125 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service; + +import com.example.modules.system.domain.Menu; +import com.example.modules.system.service.dto.MenuDto; +import com.example.modules.system.service.dto.MenuQueryCriteria; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * + * 2018-12-17 + */ +public interface MenuService { + + /** + * 查询全部数据 + * @param criteria 条件 + * @param isQuery / + * @throws Exception / + * @return / + */ + List<MenuDto> queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception; + + /** + * 根据ID查询 + * @param id / + * @return / + */ + MenuDto findById(long id); + + /** + * 创建 + * @param resources / + */ + void create(Menu resources); + + /** + * 编辑 + * @param resources / + */ + void update(Menu resources); + + /** + * 获取所有子节点,包含自身ID + * @param menuList / + * @param menuSet / + * @return / + */ + Set<Menu> getChildMenus(List<Menu> menuList, Set<Menu> menuSet); + + /** + * 构建菜单树 + * @param menuDtos 原始数据 + * @return / + */ + List<MenuDto> buildTree(List<MenuDto> menuDtos); + + /** + * 构建菜单树 + * @param menuDtos / + * @return / + */ + Object buildMenus(List<MenuDto> menuDtos); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + Menu findOne(Long id); + + /** + * 删除 + * @param menuSet / + */ + void delete(Set<Menu> menuSet); + + /** + * 导出 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List<MenuDto> queryAll, HttpServletResponse response) throws IOException; + + /** + * 懒加载菜单数据 + * @param pid / + * @return / + */ + List<MenuDto> getMenus(Long pid); + + /** + * 根据ID获取同级与上级数据 + * @param menuDto / + * @param objects / + * @return / + */ + List<MenuDto> getSuperior(MenuDto menuDto, List<Menu> objects); + + /** + * 根据当前用户获取菜单 + * @param currentUserId / + * @return / + */ + List<MenuDto> findByUser(Long currentUserId); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MonitorService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MonitorService.java new file mode 100644 index 0000000..d9f87f9 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/MonitorService.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service; + +import java.util.Map; + +/** + * + * 2020-05-02 + */ +public interface MonitorService { + + /** + * 查询数据分页 + * @return Map<String,Object> + */ + Map<String,Object> getServers(); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/RoleService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/RoleService.java new file mode 100644 index 0000000..5fa13ca --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/RoleService.java @@ -0,0 +1,136 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service; + +import com.example.modules.system.domain.Role; +import com.example.modules.system.service.dto.RoleDto; +import com.example.modules.system.service.dto.RoleQueryCriteria; +import com.example.modules.system.service.dto.RoleSmallDto; +import com.example.modules.system.service.dto.UserDto; +import org.springframework.data.domain.Pageable; +import org.springframework.security.core.GrantedAuthority; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * + * 2018-12-03 + */ +public interface RoleService { + + /** + * 查询全部数据 + * @return / + */ + List<RoleDto> queryAll(); + + /** + * 根据ID查询 + * @param id / + * @return / + */ + RoleDto findById(long id); + + /** + * 创建 + * @param resources / + */ + void create(Role resources); + + /** + * 编辑 + * @param resources / + */ + void update(Role resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set<Long> ids); + + /** + * 根据用户ID查询 + * @param id 用户ID + * @return / + */ + List<RoleSmallDto> findByUsersId(Long id); + + /** + * 根据角色查询角色级别 + * @param roles / + * @return / + */ + Integer findByRoles(Set<Role> roles); + + /** + * 修改绑定的菜单 + * @param resources / + * @param roleDTO / + */ + void updateMenu(Role resources, RoleDto roleDTO); + + /** + * 解绑菜单 + * @param id / + */ + void untiedMenu(Long id); + + /** + * 待条件分页查询 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(RoleQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List<RoleDto> queryAll(RoleQueryCriteria criteria); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List<RoleDto> queryAll, HttpServletResponse response) throws IOException; + + /** + * 获取用户权限信息 + * @param user 用户信息 + * @return 权限信息 + */ + List<GrantedAuthority> mapToGrantedAuthorities(UserDto user); + + /** + * 验证是否被用户关联 + * @param ids / + */ + void verification(Set<Long> ids); + + /** + * 根据菜单Id查询 + * @param menuIds / + * @return / + */ + List<Role> findInMenuId(List<Long> menuIds); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/UserService.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/UserService.java new file mode 100644 index 0000000..10fba88 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/UserService.java @@ -0,0 +1,114 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service; + +import com.example.modules.system.domain.User; +import com.example.modules.system.service.dto.UserDto; +import com.example.modules.system.service.dto.UserQueryCriteria; +import org.springframework.data.domain.Pageable; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +public interface UserService { + + /** + * 根据ID查询 + * @param id ID + * @return / + */ + UserDto findById(long id); + + /** + * 新增用户 + * @param resources / + */ + void create(User resources); + + /** + * 编辑用户 + * @param resources / + * @throws Exception / + */ + void update(User resources) throws Exception; + + /** + * 删除用户 + * @param ids / + */ + void delete(Set<Long> ids); + + /** + * 根据用户名查询 + * @param userName / + * @return / + */ + UserDto findByName(String userName); + + /** + * 修改密码 + * @param username 用户名 + * @param encryptPassword 密码 + */ + void updatePass(String username, String encryptPassword); + + /** + * 修改头像 + * @param file 文件 + * @return / + */ + Map<String, String> updateAvatar(MultipartFile file); + + /** + * 修改邮箱 + * @param username 用户名 + * @param email 邮箱 + */ + void updateEmail(String username, String email); + + /** + * 查询全部 + * @param criteria 条件 + * @param pageable 分页参数 + * @return / + */ + Object queryAll(UserQueryCriteria criteria, Pageable pageable); + + /** + * 查询全部不分页 + * @param criteria 条件 + * @return / + */ + List<UserDto> queryAll(UserQueryCriteria criteria); + + /** + * 导出数据 + * @param queryAll 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List<UserDto> queryAll, HttpServletResponse response) throws IOException; + + /** + * 用户自助修改资料 + * @param resources / + */ + void updateCenter(User resources); +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptDto.java new file mode 100644 index 0000000..02ec1ea --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptDto.java @@ -0,0 +1,78 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseDTO; +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +/** +* +* 2019-03-25 +*/ +@Getter +@Setter +public class DeptDto extends BaseDTO implements Serializable { + + private Long id; + + private String name; + + private Boolean enabled; + + private Integer deptSort; + + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private List<DeptDto> children; + + private Long pid; + + private Integer subCount; + + public Boolean getHasChildren() { + return subCount > 0; + } + + public Boolean getLeaf() { + return subCount <= 0; + } + + public String getLabel() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DeptDto deptDto = (DeptDto) o; + return Objects.equals(id, deptDto.id) && + Objects.equals(name, deptDto.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptQueryCriteria.java new file mode 100644 index 0000000..8f8c56b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptQueryCriteria.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Data; +import com.example.annotation.DataPermission; +import com.example.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* +* 2019-03-25 +*/ +@Data +@DataPermission(fieldName = "id") +public class DeptQueryCriteria{ + + @Query(type = Query.Type.INNER_LIKE) + private String name; + + @Query + private Boolean enabled; + + @Query + private Long pid; + + @Query(type = Query.Type.IS_NULL, propName = "pid") + private Boolean pidIsNull; + + @Query(type = Query.Type.BETWEEN) + private List<Timestamp> createTime; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptSmallDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptSmallDto.java new file mode 100644 index 0000000..503762b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DeptSmallDto.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Data; +import java.io.Serializable; + +/** +* +* 2019-6-10 16:32:18 +*/ +@Data +public class DeptSmallDto implements Serializable { + + private Long id; + + private String name; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailDto.java new file mode 100644 index 0000000..58e826b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailDto.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseDTO; +import java.io.Serializable; + +/** +* +* 2019-04-10 +*/ +@Getter +@Setter +public class DictDetailDto extends BaseDTO implements Serializable { + + private Long id; + + private DictSmallDto dict; + + private String label; + + private String value; + + private Integer dictSort; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailQueryCriteria.java new file mode 100644 index 0000000..2f12c80 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDetailQueryCriteria.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Data; +import com.example.annotation.Query; + +/** +* +* 2019-04-10 +*/ +@Data +public class DictDetailQueryCriteria { + + @Query(type = Query.Type.INNER_LIKE) + private String label; + + @Query(propName = "name",joinName = "dict") + private String dictName; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDto.java new file mode 100644 index 0000000..72f704e --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictDto.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseDTO; +import java.io.Serializable; +import java.util.List; + +/** +* +* 2019-04-10 +*/ +@Getter +@Setter +public class DictDto extends BaseDTO implements Serializable { + + private Long id; + + private List<DictDetailDto> dictDetails; + + private String name; + + private String description; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictQueryCriteria.java new file mode 100644 index 0000000..3a5da52 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictQueryCriteria.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Data; +import com.example.annotation.Query; + +/** + * + * 公共查询类 + */ +@Data +public class DictQueryCriteria { + + @Query(blurry = "name,description") + private String blurry; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictSmallDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictSmallDto.java new file mode 100644 index 0000000..a0ed61f --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/DictSmallDto.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import java.io.Serializable; + +/** +* +* 2019-04-10 +*/ +@Getter +@Setter +public class DictSmallDto implements Serializable { + + private Long id; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobDto.java new file mode 100644 index 0000000..502176b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobDto.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import com.example.base.BaseDTO; + +import java.io.Serializable; + +/** +* +* 2019-03-29 +*/ +@Getter +@Setter +@NoArgsConstructor +public class JobDto extends BaseDTO implements Serializable { + + private Long id; + + private Integer jobSort; + + private String name; + + private Boolean enabled; + + public JobDto(String name, Boolean enabled) { + this.name = name; + this.enabled = enabled; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobQueryCriteria.java new file mode 100644 index 0000000..215d721 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobQueryCriteria.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; +import com.example.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** +* +* 2019-6-4 14:49:34 +*/ +@Data +@NoArgsConstructor +public class JobQueryCriteria { + + @Query(type = Query.Type.INNER_LIKE) + private String name; + + @Query + private Boolean enabled; + + @Query(type = Query.Type.BETWEEN) + private List<Timestamp> createTime; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobSmallDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobSmallDto.java new file mode 100644 index 0000000..af9f8a6 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/JobSmallDto.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; + +/** +* +* 2019-6-10 16:32:18 +*/ +@Data +@NoArgsConstructor +public class JobSmallDto implements Serializable { + + private Long id; + + private String name; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuDto.java new file mode 100644 index 0000000..8500654 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuDto.java @@ -0,0 +1,91 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseDTO; +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +/** + * + * 2018-12-17 + */ +@Getter +@Setter +public class MenuDto extends BaseDTO implements Serializable { + + private Long id; + + private List<MenuDto> children; + + private Integer type; + + private String permission; + + private String title; + + private Integer menuSort; + + private String path; + + private String component; + + private Long pid; + + private Integer subCount; + + private Boolean iFrame; + + private Boolean cache; + + private Boolean hidden; + + private String componentName; + + private String icon; + + public Boolean getHasChildren() { + return subCount > 0; + } + + public Boolean getLeaf() { + return subCount <= 0; + } + + public String getLabel() { + return title; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MenuDto menuDto = (MenuDto) o; + return Objects.equals(id, menuDto.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuQueryCriteria.java new file mode 100644 index 0000000..1d03860 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/MenuQueryCriteria.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Data; +import com.example.annotation.Query; +import java.sql.Timestamp; +import java.util.List; + +/** + * + * 公共查询类 + */ +@Data +public class MenuQueryCriteria { + + @Query(blurry = "title,component,permission") + private String blurry; + + @Query(type = Query.Type.BETWEEN) + private List<Timestamp> createTime; + + @Query(type = Query.Type.IS_NULL, propName = "pid") + private Boolean pidIsNull; + + @Query + private Long pid; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleDto.java new file mode 100644 index 0000000..1373b7f --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleDto.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseDTO; +import java.io.Serializable; +import java.util.Objects; +import java.util.Set; + + +@Getter +@Setter +public class RoleDto extends BaseDTO implements Serializable { + + private Long id; + + private Set<MenuDto> menus; + + private Set<DeptDto> depts; + + private String name; + + private String dataScope; + + private Integer level; + + private String description; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RoleDto roleDto = (RoleDto) o; + return Objects.equals(id, roleDto.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleQueryCriteria.java new file mode 100644 index 0000000..afe3a4e --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleQueryCriteria.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Data; +import com.example.annotation.Query; + +import java.sql.Timestamp; +import java.util.List; + +/** + * + * 公共查询类 + */ +@Data +public class RoleQueryCriteria { + + @Query(blurry = "name,description") + private String blurry; + + @Query(type = Query.Type.BETWEEN) + private List<Timestamp> createTime; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleSmallDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleSmallDto.java new file mode 100644 index 0000000..5c7f184 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/RoleSmallDto.java @@ -0,0 +1,32 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Data; +import java.io.Serializable; + + +@Data +public class RoleSmallDto implements Serializable { + + private Long id; + + private String name; + + private Integer level; + + private String dataScope; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserDto.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserDto.java new file mode 100644 index 0000000..a1ecd96 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserDto.java @@ -0,0 +1,64 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Getter; +import lombok.Setter; +import com.example.base.BaseDTO; +import java.io.Serializable; +import java.util.Date; +import java.util.Set; + + +@Getter +@Setter +public class UserDto extends BaseDTO implements Serializable { + + private Long id; + + private Set<RoleSmallDto> roles; + + private Set<JobSmallDto> jobs; + + private DeptSmallDto dept; + + private Long deptId; + + private String username; + + private String nickName; + + private String email; + + private String phone; + + private String gender; + + private String avatarName; + + private String avatarPath; + + @JSONField(serialize = false) + private String password; + + private Boolean enabled; + + @JSONField(serialize = false) + private Boolean isAdmin = false; + + private Date pwdResetTime; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserQueryCriteria.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserQueryCriteria.java new file mode 100644 index 0000000..1f862cf --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/dto/UserQueryCriteria.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.dto; + +import lombok.Data; +import com.example.annotation.Query; +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +@Data +public class UserQueryCriteria implements Serializable { + + @Query + private Long id; + + @Query(propName = "id", type = Query.Type.IN, joinName = "dept") + private Set<Long> deptIds = new HashSet<>(); + + @Query(blurry = "email,username,nickName") + private String blurry; + + @Query + private Boolean enabled; + + private Long deptId; + + @Query(type = Query.Type.BETWEEN) + private List<Timestamp> createTime; +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DataServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DataServiceImpl.java new file mode 100644 index 0000000..e31f26b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DataServiceImpl.java @@ -0,0 +1,91 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.impl; + +import com.example.modules.system.domain.Dept; +import com.example.modules.system.service.DataService; +import com.example.modules.system.service.DeptService; +import lombok.RequiredArgsConstructor; +import com.example.modules.system.service.RoleService; +import com.example.modules.system.service.dto.RoleSmallDto; +import com.example.modules.system.service.dto.UserDto; +import com.example.utils.enums.DataScopeEnum; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import java.util.*; + +/** + * + * @website https://el-admin.vip + * @description 数据权限服务实现 + * 2020-05-07 + **/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "data") +public class DataServiceImpl implements DataService { + + private final RoleService roleService; + private final DeptService deptService; + + /** + * 用户角色改变时需清理缓存 + * @param user / + * @return / + */ + @Override + @Cacheable(key = "'user:' + #p0.id") + public List<Long> getDeptIds(UserDto user) { + // 用于存储部门id + Set<Long> deptIds = new HashSet<>(); + // 查询用户角色 + List<RoleSmallDto> roleSet = roleService.findByUsersId(user.getId()); + // 获取对应的部门ID + for (RoleSmallDto role : roleSet) { + DataScopeEnum dataScopeEnum = DataScopeEnum.find(role.getDataScope()); + switch (Objects.requireNonNull(dataScopeEnum)) { + case THIS_LEVEL: + deptIds.add(user.getDept().getId()); + break; + case CUSTOMIZE: + deptIds.addAll(getCustomize(deptIds, role)); + break; + default: + return new ArrayList<>(deptIds); + } + } + return new ArrayList<>(deptIds); + } + + /** + * 获取自定义的数据权限 + * @param deptIds 部门ID + * @param role 角色 + * @return 数据权限ID + */ + public Set<Long> getCustomize(Set<Long> deptIds, RoleSmallDto role){ + Set<Dept> depts = deptService.findByRoleId(role.getId()); + for (Dept dept : depts) { + deptIds.add(dept.getId()); + List<Dept> deptChildren = deptService.findByPid(dept.getId()); + if (deptChildren != null && deptChildren.size() != 0) { + deptIds.addAll(deptService.getDeptChildren(deptChildren)); + } + } + return deptIds; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DeptServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DeptServiceImpl.java new file mode 100644 index 0000000..e777319 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DeptServiceImpl.java @@ -0,0 +1,284 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.example.modules.system.domain.Dept; +import com.example.modules.system.domain.User; +import com.example.modules.system.repository.DeptRepository; +import com.example.modules.system.repository.RoleRepository; +import com.example.modules.system.service.DeptService; +import com.example.modules.system.service.dto.DeptDto; +import com.example.modules.system.service.dto.DeptQueryCriteria; +import com.example.utils.*; +import lombok.RequiredArgsConstructor; +import com.example.exception.BadRequestException; +import com.example.modules.system.repository.UserRepository; +import com.example.utils.*; +import com.example.modules.system.service.mapstruct.DeptMapper; +import com.example.utils.enums.DataScopeEnum; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** +* +* 2019-03-25 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "dept") +public class DeptServiceImpl implements DeptService { + + private final DeptRepository deptRepository; + private final DeptMapper deptMapper; + private final UserRepository userRepository; + private final RedisUtils redisUtils; + private final RoleRepository roleRepository; + + @Override + public List<DeptDto> queryAll(DeptQueryCriteria criteria, Boolean isQuery) throws Exception { + Sort sort = Sort.by(Sort.Direction.ASC, "deptSort"); + String dataScopeType = SecurityUtils.getDataScopeType(); + if (isQuery) { + if(dataScopeType.equals(DataScopeEnum.ALL.getValue())){ + criteria.setPidIsNull(true); + } + List<Field> fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>()); + List<String> fieldNames = new ArrayList<String>(){{ add("pidIsNull");add("enabled");}}; + for (Field field : fields) { + //设置对象的访问权限,保证对private的属性的访问 + field.setAccessible(true); + Object val = field.get(criteria); + if(fieldNames.contains(field.getName())){ + continue; + } + if (ObjectUtil.isNotNull(val)) { + criteria.setPidIsNull(null); + break; + } + } + } + List<DeptDto> list = deptMapper.toDto(deptRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort)); + // 如果为空,就代表为自定义权限或者本级权限,就需要去重,不理解可以注释掉,看查询结果 + if(StringUtils.isBlank(dataScopeType)){ + return deduplication(list); + } + return list; + } + + @Override + @Cacheable(key = "'id:' + #p0") + public DeptDto findById(Long id) { + Dept dept = deptRepository.findById(id).orElseGet(Dept::new); + ValidationUtil.isNull(dept.getId(),"Dept","id",id); + return deptMapper.toDto(dept); + } + + @Override + public List<Dept> findByPid(long pid) { + return deptRepository.findByPid(pid); + } + + @Override + public Set<Dept> findByRoleId(Long id) { + return deptRepository.findByRoleId(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Dept resources) { + deptRepository.save(resources); + // 计算子节点数目 + resources.setSubCount(0); + // 清理缓存 + updateSubCnt(resources.getPid()); + // 清理自定义角色权限的datascope缓存 + delCaches(resources.getPid()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Dept resources) { + // 旧的部门 + Long oldPid = findById(resources.getId()).getPid(); + Long newPid = resources.getPid(); + if(resources.getPid() != null && resources.getId().equals(resources.getPid())) { + throw new BadRequestException("上级不能为自己"); + } + Dept dept = deptRepository.findById(resources.getId()).orElseGet(Dept::new); + ValidationUtil.isNull( dept.getId(),"Dept","id",resources.getId()); + resources.setId(dept.getId()); + deptRepository.save(resources); + // 更新父节点中子节点数目 + updateSubCnt(oldPid); + updateSubCnt(newPid); + // 清理缓存 + delCaches(resources.getId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set<DeptDto> deptDtos) { + for (DeptDto deptDto : deptDtos) { + // 清理缓存 + delCaches(deptDto.getId()); + deptRepository.deleteById(deptDto.getId()); + updateSubCnt(deptDto.getPid()); + } + } + + @Override + public void download(List<DeptDto> deptDtos, HttpServletResponse response) throws IOException { + List<Map<String, Object>> list = new ArrayList<>(); + for (DeptDto deptDTO : deptDtos) { + Map<String,Object> map = new LinkedHashMap<>(); + map.put("部门名称", deptDTO.getName()); + map.put("部门状态", deptDTO.getEnabled() ? "启用" : "停用"); + map.put("创建日期", deptDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public Set<DeptDto> getDeleteDepts(List<Dept> menuList, Set<DeptDto> deptDtos) { + for (Dept dept : menuList) { + deptDtos.add(deptMapper.toDto(dept)); + List<Dept> depts = deptRepository.findByPid(dept.getId()); + if(depts!=null && depts.size()!=0){ + getDeleteDepts(depts, deptDtos); + } + } + return deptDtos; + } + + @Override + public List<Long> getDeptChildren(List<Dept> deptList) { + List<Long> list = new ArrayList<>(); + deptList.forEach(dept -> { + if (dept!=null && dept.getEnabled()) { + List<Dept> depts = deptRepository.findByPid(dept.getId()); + if (depts.size() != 0) { + list.addAll(getDeptChildren(depts)); + } + list.add(dept.getId()); + } + } + ); + return list; + } + + @Override + public List<DeptDto> getSuperior(DeptDto deptDto, List<Dept> depts) { + if(deptDto.getPid() == null){ + depts.addAll(deptRepository.findByPidIsNull()); + return deptMapper.toDto(depts); + } + depts.addAll(deptRepository.findByPid(deptDto.getPid())); + return getSuperior(findById(deptDto.getPid()), depts); + } + + @Override + public Object buildTree(List<DeptDto> deptDtos) { + Set<DeptDto> trees = new LinkedHashSet<>(); + Set<DeptDto> depts= new LinkedHashSet<>(); + List<String> deptNames = deptDtos.stream().map(DeptDto::getName).collect(Collectors.toList()); + boolean isChild; + for (DeptDto deptDTO : deptDtos) { + isChild = false; + if (deptDTO.getPid() == null) { + trees.add(deptDTO); + } + for (DeptDto it : deptDtos) { + if (it.getPid() != null && deptDTO.getId().equals(it.getPid())) { + isChild = true; + if (deptDTO.getChildren() == null) { + deptDTO.setChildren(new ArrayList<>()); + } + deptDTO.getChildren().add(it); + } + } + if(isChild) { + depts.add(deptDTO); + } else if(deptDTO.getPid() != null && !deptNames.contains(findById(deptDTO.getPid()).getName())) { + depts.add(deptDTO); + } + } + + if (CollectionUtil.isEmpty(trees)) { + trees = depts; + } + Map<String,Object> map = new HashMap<>(2); + map.put("totalElements",deptDtos.size()); + map.put("content",CollectionUtil.isEmpty(trees)? deptDtos :trees); + return map; + } + + @Override + public void verification(Set<DeptDto> deptDtos) { + Set<Long> deptIds = deptDtos.stream().map(DeptDto::getId).collect(Collectors.toSet()); + if(userRepository.countByDepts(deptIds) > 0){ + throw new BadRequestException("所选部门存在用户关联,请解除后再试!"); + } + if(roleRepository.countByDepts(deptIds) > 0){ + throw new BadRequestException("所选部门存在角色关联,请解除后再试!"); + } + } + + private void updateSubCnt(Long deptId){ + if(deptId != null){ + int count = deptRepository.countByPid(deptId); + deptRepository.updateSubCntById(count, deptId); + } + } + + private List<DeptDto> deduplication(List<DeptDto> list) { + List<DeptDto> deptDtos = new ArrayList<>(); + for (DeptDto deptDto : list) { + boolean flag = true; + for (DeptDto dto : list) { + if (dto.getId().equals(deptDto.getPid())) { + flag = false; + break; + } + } + if (flag){ + deptDtos.add(deptDto); + } + } + return deptDtos; + } + + /** + * 清理缓存 + * @param id / + */ + public void delCaches(Long id){ + List<User> users = userRepository.findByRoleDeptId(id); + // 删除数据权限 + redisUtils.delByKeys(CacheKey.DATA_USER, users.stream().map(User::getId).collect(Collectors.toSet())); + redisUtils.del(CacheKey.DEPT_ID + id); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictDetailServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictDetailServiceImpl.java new file mode 100644 index 0000000..672a31a --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictDetailServiceImpl.java @@ -0,0 +1,96 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.impl; + +import com.example.modules.system.domain.Dict; +import com.example.modules.system.domain.DictDetail; +import com.example.utils.*; +import lombok.RequiredArgsConstructor; +import com.example.modules.system.repository.DictRepository; +import com.example.modules.system.service.dto.DictDetailQueryCriteria; +import com.example.utils.*; +import com.example.modules.system.repository.DictDetailRepository; +import com.example.modules.system.service.DictDetailService; +import com.example.modules.system.service.dto.DictDetailDto; +import com.example.modules.system.service.mapstruct.DictDetailMapper; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.Map; + +/** +* +* 2019-04-10 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "dict") +public class DictDetailServiceImpl implements DictDetailService { + + private final DictRepository dictRepository; + private final DictDetailRepository dictDetailRepository; + private final DictDetailMapper dictDetailMapper; + private final RedisUtils redisUtils; + + @Override + public Map<String,Object> queryAll(DictDetailQueryCriteria criteria, Pageable pageable) { + Page<DictDetail> page = dictDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(dictDetailMapper::toDto)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(DictDetail resources) { + dictDetailRepository.save(resources); + // 清理缓存 + delCaches(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(DictDetail resources) { + DictDetail dictDetail = dictDetailRepository.findById(resources.getId()).orElseGet(DictDetail::new); + ValidationUtil.isNull( dictDetail.getId(),"DictDetail","id",resources.getId()); + resources.setId(dictDetail.getId()); + dictDetailRepository.save(resources); + // 清理缓存 + delCaches(resources); + } + + @Override + @Cacheable(key = "'name:' + #p0") + public List<DictDetailDto> getDictByName(String name) { + return dictDetailMapper.toDto(dictDetailRepository.findByDictName(name)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Long id) { + DictDetail dictDetail = dictDetailRepository.findById(id).orElseGet(DictDetail::new); + // 清理缓存 + delCaches(dictDetail); + dictDetailRepository.deleteById(id); + } + + public void delCaches(DictDetail dictDetail){ + Dict dict = dictRepository.findById(dictDetail.getDict().getId()).orElseGet(Dict::new); + redisUtils.del(CacheKey.DICT_NAME + dict.getName()); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictServiceImpl.java new file mode 100644 index 0000000..79cd9e3 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/DictServiceImpl.java @@ -0,0 +1,122 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import com.example.modules.system.domain.Dict; +import com.example.modules.system.service.dto.DictDto; +import com.example.utils.*; +import lombok.RequiredArgsConstructor; +import com.example.modules.system.service.dto.DictDetailDto; +import com.example.modules.system.service.dto.DictQueryCriteria; +import com.example.utils.*; +import com.example.modules.system.repository.DictRepository; +import com.example.modules.system.service.DictService; +import com.example.modules.system.service.mapstruct.DictMapper; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* +* 2019-04-10 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "dict") +public class DictServiceImpl implements DictService { + + private final DictRepository dictRepository; + private final DictMapper dictMapper; + private final RedisUtils redisUtils; + + @Override + public Map<String, Object> queryAll(DictQueryCriteria dict, Pageable pageable){ + Page<Dict> page = dictRepository.findAll((root, query, cb) -> QueryHelp.getPredicate(root, dict, cb), pageable); + return PageUtil.toPage(page.map(dictMapper::toDto)); + } + + @Override + public List<DictDto> queryAll(DictQueryCriteria dict) { + List<Dict> list = dictRepository.findAll((root, query, cb) -> QueryHelp.getPredicate(root, dict, cb)); + return dictMapper.toDto(list); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Dict resources) { + dictRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Dict resources) { + // 清理缓存 + delCaches(resources); + Dict dict = dictRepository.findById(resources.getId()).orElseGet(Dict::new); + ValidationUtil.isNull( dict.getId(),"Dict","id",resources.getId()); + dict.setName(resources.getName()); + dict.setDescription(resources.getDescription()); + dictRepository.save(dict); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set<Long> ids) { + // 清理缓存 + List<Dict> dicts = dictRepository.findByIdIn(ids); + for (Dict dict : dicts) { + delCaches(dict); + } + dictRepository.deleteByIdIn(ids); + } + + @Override + public void download(List<DictDto> dictDtos, HttpServletResponse response) throws IOException { + List<Map<String, Object>> list = new ArrayList<>(); + for (DictDto dictDTO : dictDtos) { + if(CollectionUtil.isNotEmpty(dictDTO.getDictDetails())){ + for (DictDetailDto dictDetail : dictDTO.getDictDetails()) { + Map<String,Object> map = new LinkedHashMap<>(); + map.put("字典名称", dictDTO.getName()); + map.put("字典描述", dictDTO.getDescription()); + map.put("字典标签", dictDetail.getLabel()); + map.put("字典值", dictDetail.getValue()); + map.put("创建日期", dictDetail.getCreateTime()); + list.add(map); + } + } else { + Map<String,Object> map = new LinkedHashMap<>(); + map.put("字典名称", dictDTO.getName()); + map.put("字典描述", dictDTO.getDescription()); + map.put("字典标签", null); + map.put("字典值", null); + map.put("创建日期", dictDTO.getCreateTime()); + list.add(map); + } + } + FileUtil.downloadExcel(list, response); + } + + public void delCaches(Dict dict){ + redisUtils.del(CacheKey.DICT_NAME + dict.getName()); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/JobServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/JobServiceImpl.java new file mode 100644 index 0000000..73c93c5 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/JobServiceImpl.java @@ -0,0 +1,126 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.impl; + +import com.example.modules.system.domain.Job; +import com.example.modules.system.service.JobService; +import com.example.modules.system.service.dto.JobDto; +import com.example.utils.*; +import lombok.RequiredArgsConstructor; +import com.example.exception.BadRequestException; +import com.example.exception.EntityExistException; +import com.example.modules.system.repository.UserRepository; +import com.example.modules.system.service.dto.JobQueryCriteria; +import com.example.utils.*; +import com.example.modules.system.repository.JobRepository; +import com.example.modules.system.service.mapstruct.JobMapper; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + +/** +* +* 2019-03-29 +*/ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "job") +public class JobServiceImpl implements JobService { + + private final JobRepository jobRepository; + private final JobMapper jobMapper; + private final RedisUtils redisUtils; + private final UserRepository userRepository; + + @Override + public Map<String,Object> queryAll(JobQueryCriteria criteria, Pageable pageable) { + Page<Job> page = jobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(jobMapper::toDto).getContent(),page.getTotalElements()); + } + + @Override + public List<JobDto> queryAll(JobQueryCriteria criteria) { + List<Job> list = jobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)); + return jobMapper.toDto(list); + } + + @Override + @Cacheable(key = "'id:' + #p0") + public JobDto findById(Long id) { + Job job = jobRepository.findById(id).orElseGet(Job::new); + ValidationUtil.isNull(job.getId(),"Job","id",id); + return jobMapper.toDto(job); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Job resources) { + Job job = jobRepository.findByName(resources.getName()); + if(job != null){ + throw new EntityExistException(Job.class,"name",resources.getName()); + } + jobRepository.save(resources); + } + + @Override + @CacheEvict(key = "'id:' + #p0.id") + @Transactional(rollbackFor = Exception.class) + public void update(Job resources) { + Job job = jobRepository.findById(resources.getId()).orElseGet(Job::new); + Job old = jobRepository.findByName(resources.getName()); + if(old != null && !old.getId().equals(resources.getId())){ + throw new EntityExistException(Job.class,"name",resources.getName()); + } + ValidationUtil.isNull( job.getId(),"Job","id",resources.getId()); + resources.setId(job.getId()); + jobRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set<Long> ids) { + jobRepository.deleteAllByIdIn(ids); + // 删除缓存 + redisUtils.delByKeys(CacheKey.JOB_ID, ids); + } + + @Override + public void download(List<JobDto> jobDtos, HttpServletResponse response) throws IOException { + List<Map<String, Object>> list = new ArrayList<>(); + for (JobDto jobDTO : jobDtos) { + Map<String,Object> map = new LinkedHashMap<>(); + map.put("岗位名称", jobDTO.getName()); + map.put("岗位状态", jobDTO.getEnabled() ? "启用" : "停用"); + map.put("创建日期", jobDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public void verification(Set<Long> ids) { + if(userRepository.countByJobs(ids) > 0){ + throw new BadRequestException("所选的岗位中存在用户关联,请解除关联再试!"); + } + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MenuServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MenuServiceImpl.java new file mode 100644 index 0000000..ceacddb --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MenuServiceImpl.java @@ -0,0 +1,356 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.example.modules.system.domain.Menu; +import com.example.modules.system.domain.Role; +import com.example.modules.system.domain.User; +import com.example.modules.system.domain.vo.MenuMetaVo; +import com.example.modules.system.domain.vo.MenuVo; +import com.example.modules.system.repository.MenuRepository; +import com.example.modules.system.service.MenuService; +import com.example.modules.system.service.RoleService; +import com.example.modules.system.service.dto.MenuDto; +import com.example.modules.system.service.dto.MenuQueryCriteria; +import com.example.modules.system.service.dto.RoleSmallDto; +import com.example.utils.*; +import lombok.RequiredArgsConstructor; +import com.example.exception.BadRequestException; +import com.example.exception.EntityExistException; +import com.example.modules.system.repository.UserRepository; +import com.example.modules.system.service.mapstruct.MenuMapper; +import com.example.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** + * + */ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "menu") +public class MenuServiceImpl implements MenuService { + + private final MenuRepository menuRepository; + private final UserRepository userRepository; + private final MenuMapper menuMapper; + private final RoleService roleService; + private final RedisUtils redisUtils; + + @Override + public List<MenuDto> queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception { + Sort sort = Sort.by(Sort.Direction.ASC, "menuSort"); + if(Boolean.TRUE.equals(isQuery)){ + criteria.setPidIsNull(true); + List<Field> fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>()); + for (Field field : fields) { + //设置对象的访问权限,保证对private的属性的访问 + field.setAccessible(true); + Object val = field.get(criteria); + if("pidIsNull".equals(field.getName())){ + continue; + } + if (ObjectUtil.isNotNull(val)) { + criteria.setPidIsNull(null); + break; + } + } + } + return menuMapper.toDto(menuRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort)); + } + + @Override + @Cacheable(key = "'id:' + #p0") + public MenuDto findById(long id) { + Menu menu = menuRepository.findById(id).orElseGet(Menu::new); + ValidationUtil.isNull(menu.getId(),"Menu","id",id); + return menuMapper.toDto(menu); + } + + /** + * 用户角色改变时需清理缓存 + * @param currentUserId / + * @return / + */ + @Override + @Cacheable(key = "'user:' + #p0") + public List<MenuDto> findByUser(Long currentUserId) { + List<RoleSmallDto> roles = roleService.findByUsersId(currentUserId); + Set<Long> roleIds = roles.stream().map(RoleSmallDto::getId).collect(Collectors.toSet()); + LinkedHashSet<Menu> menus = menuRepository.findByRoleIdsAndTypeNot(roleIds, 2); + return menus.stream().map(menuMapper::toDto).collect(Collectors.toList()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Menu resources) { + if(menuRepository.findByTitle(resources.getTitle()) != null){ + throw new EntityExistException(Menu.class,"title",resources.getTitle()); + } + if(StringUtils.isNotBlank(resources.getComponentName())){ + if(menuRepository.findByComponentName(resources.getComponentName()) != null){ + throw new EntityExistException(Menu.class,"componentName",resources.getComponentName()); + } + } + if(resources.getPid().equals(0L)){ + resources.setPid(null); + } + if(resources.getIFrame()){ + String http = "http://", https = "https://"; + if (!(resources.getPath().toLowerCase().startsWith(http)||resources.getPath().toLowerCase().startsWith(https))) { + throw new BadRequestException("外链必须以http://或者https://开头"); + } + } + menuRepository.save(resources); + // 计算子节点数目 + resources.setSubCount(0); + // 更新父节点菜单数目 + updateSubCnt(resources.getPid()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Menu resources) { + if(resources.getId().equals(resources.getPid())) { + throw new BadRequestException("上级不能为自己"); + } + Menu menu = menuRepository.findById(resources.getId()).orElseGet(Menu::new); + ValidationUtil.isNull(menu.getId(),"Permission","id",resources.getId()); + + if(resources.getIFrame()){ + String http = "http://", https = "https://"; + if (!(resources.getPath().toLowerCase().startsWith(http)||resources.getPath().toLowerCase().startsWith(https))) { + throw new BadRequestException("外链必须以http://或者https://开头"); + } + } + Menu menu1 = menuRepository.findByTitle(resources.getTitle()); + + if(menu1 != null && !menu1.getId().equals(menu.getId())){ + throw new EntityExistException(Menu.class,"title",resources.getTitle()); + } + + if(resources.getPid().equals(0L)){ + resources.setPid(null); + } + + // 记录的父节点ID + Long oldPid = menu.getPid(); + Long newPid = resources.getPid(); + + if(StringUtils.isNotBlank(resources.getComponentName())){ + menu1 = menuRepository.findByComponentName(resources.getComponentName()); + if(menu1 != null && !menu1.getId().equals(menu.getId())){ + throw new EntityExistException(Menu.class,"componentName",resources.getComponentName()); + } + } + menu.setTitle(resources.getTitle()); + menu.setComponent(resources.getComponent()); + menu.setPath(resources.getPath()); + menu.setIcon(resources.getIcon()); + menu.setIFrame(resources.getIFrame()); + menu.setPid(resources.getPid()); + menu.setMenuSort(resources.getMenuSort()); + menu.setCache(resources.getCache()); + menu.setHidden(resources.getHidden()); + menu.setComponentName(resources.getComponentName()); + menu.setPermission(resources.getPermission()); + menu.setType(resources.getType()); + menuRepository.save(menu); + // 计算父级菜单节点数目 + updateSubCnt(oldPid); + updateSubCnt(newPid); + // 清理缓存 + delCaches(resources.getId()); + } + + @Override + public Set<Menu> getChildMenus(List<Menu> menuList, Set<Menu> menuSet) { + for (Menu menu : menuList) { + menuSet.add(menu); + List<Menu> menus = menuRepository.findByPid(menu.getId()); + if(menus!=null && menus.size()!=0){ + getChildMenus(menus, menuSet); + } + } + return menuSet; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set<Menu> menuSet) { + for (Menu menu : menuSet) { + // 清理缓存 + delCaches(menu.getId()); + roleService.untiedMenu(menu.getId()); + menuRepository.deleteById(menu.getId()); + updateSubCnt(menu.getPid()); + } + } + + @Override + public List<MenuDto> getMenus(Long pid) { + List<Menu> menus; + if(pid != null && !pid.equals(0L)){ + menus = menuRepository.findByPid(pid); + } else { + menus = menuRepository.findByPidIsNull(); + } + return menuMapper.toDto(menus); + } + + @Override + public List<MenuDto> getSuperior(MenuDto menuDto, List<Menu> menus) { + if(menuDto.getPid() == null){ + menus.addAll(menuRepository.findByPidIsNull()); + return menuMapper.toDto(menus); + } + menus.addAll(menuRepository.findByPid(menuDto.getPid())); + return getSuperior(findById(menuDto.getPid()), menus); + } + + @Override + public List<MenuDto> buildTree(List<MenuDto> menuDtos) { + List<MenuDto> trees = new ArrayList<>(); + Set<Long> ids = new HashSet<>(); + for (MenuDto menuDTO : menuDtos) { + if (menuDTO.getPid() == null) { + trees.add(menuDTO); + } + for (MenuDto it : menuDtos) { + if (menuDTO.getId().equals(it.getPid())) { + if (menuDTO.getChildren() == null) { + menuDTO.setChildren(new ArrayList<>()); + } + menuDTO.getChildren().add(it); + ids.add(it.getId()); + } + } + } + if(trees.size() == 0){ + trees = menuDtos.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList()); + } + return trees; + } + + @Override + public List<MenuVo> buildMenus(List<MenuDto> menuDtos) { + List<MenuVo> list = new LinkedList<>(); + menuDtos.forEach(menuDTO -> { + if (menuDTO!=null){ + List<MenuDto> menuDtoList = menuDTO.getChildren(); + MenuVo menuVo = new MenuVo(); + menuVo.setName(ObjectUtil.isNotEmpty(menuDTO.getComponentName()) ? menuDTO.getComponentName() : menuDTO.getTitle()); + // 一级目录需要加斜杠,不然会报警告 + menuVo.setPath(menuDTO.getPid() == null ? "/" + menuDTO.getPath() :menuDTO.getPath()); + menuVo.setHidden(menuDTO.getHidden()); + // 如果不是外链 + if(!menuDTO.getIFrame()){ + if(menuDTO.getPid() == null){ + menuVo.setComponent(StringUtils.isEmpty(menuDTO.getComponent())?"Layout":menuDTO.getComponent()); + // 如果不是一级菜单,并且菜单类型为目录,则代表是多级菜单 + }else if(menuDTO.getType() == 0){ + menuVo.setComponent(StringUtils.isEmpty(menuDTO.getComponent())?"ParentView":menuDTO.getComponent()); + }else if(StringUtils.isNoneBlank(menuDTO.getComponent())){ + menuVo.setComponent(menuDTO.getComponent()); + } + } + menuVo.setMeta(new MenuMetaVo(menuDTO.getTitle(),menuDTO.getIcon(),!menuDTO.getCache())); + if(CollectionUtil.isNotEmpty(menuDtoList)){ + menuVo.setAlwaysShow(true); + menuVo.setRedirect("noredirect"); + menuVo.setChildren(buildMenus(menuDtoList)); + // 处理是一级菜单并且没有子菜单的情况 + } else if(menuDTO.getPid() == null){ + MenuVo menuVo1 = new MenuVo(); + menuVo1.setMeta(menuVo.getMeta()); + // 非外链 + if(!menuDTO.getIFrame()){ + menuVo1.setPath("index"); + menuVo1.setName(menuVo.getName()); + menuVo1.setComponent(menuVo.getComponent()); + } else { + menuVo1.setPath(menuDTO.getPath()); + } + menuVo.setName(null); + menuVo.setMeta(null); + menuVo.setComponent("Layout"); + List<MenuVo> list1 = new ArrayList<>(); + list1.add(menuVo1); + menuVo.setChildren(list1); + } + list.add(menuVo); + } + } + ); + return list; + } + + @Override + public Menu findOne(Long id) { + Menu menu = menuRepository.findById(id).orElseGet(Menu::new); + ValidationUtil.isNull(menu.getId(),"Menu","id",id); + return menu; + } + + @Override + public void download(List<MenuDto> menuDtos, HttpServletResponse response) throws IOException { + List<Map<String, Object>> list = new ArrayList<>(); + for (MenuDto menuDTO : menuDtos) { + Map<String,Object> map = new LinkedHashMap<>(); + map.put("菜单标题", menuDTO.getTitle()); + map.put("菜单类型", menuDTO.getType() == null ? "目录" : menuDTO.getType() == 1 ? "菜单" : "按钮"); + map.put("权限标识", menuDTO.getPermission()); + map.put("外链菜单", menuDTO.getIFrame() ? "是" : "否"); + map.put("菜单可见", menuDTO.getHidden() ? "否" : "是"); + map.put("是否缓存", menuDTO.getCache() ? "是" : "否"); + map.put("创建日期", menuDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + private void updateSubCnt(Long menuId){ + if(menuId != null){ + int count = menuRepository.countByPid(menuId); + menuRepository.updateSubCntById(count, menuId); + } + } + + /** + * 清理缓存 + * @param id 菜单ID + */ + public void delCaches(Long id){ + List<User> users = userRepository.findByMenuId(id); + redisUtils.del(CacheKey.MENU_ID + id); + redisUtils.delByKeys(CacheKey.MENU_USER, users.stream().map(User::getId).collect(Collectors.toSet())); + // 清除 Role 缓存 + List<Role> roles = roleService.findInMenuId(new ArrayList<Long>(){{ + add(id); + }}); + redisUtils.delByKeys(CacheKey.ROLE_ID, roles.stream().map(Role::getId).collect(Collectors.toSet())); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MonitorServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MonitorServiceImpl.java new file mode 100644 index 0000000..c279293 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/MonitorServiceImpl.java @@ -0,0 +1,186 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.impl; + +import cn.hutool.core.date.BetweenFormater; +import cn.hutool.core.date.DateUtil; +import com.example.modules.system.service.MonitorService; +import com.example.utils.ElAdminConstant; +import com.example.utils.FileUtil; +import com.example.utils.StringUtils; +import org.springframework.stereotype.Service; +import oshi.SystemInfo; +import oshi.hardware.*; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; +import oshi.util.FormatUtil; +import oshi.util.Util; +import java.lang.management.ManagementFactory; +import java.text.DecimalFormat; +import java.util.*; + +/** +* +* 2020-05-02 +*/ +@Service +public class MonitorServiceImpl implements MonitorService { + + private final DecimalFormat df = new DecimalFormat("0.00"); + + @Override + public Map<String,Object> getServers(){ + Map<String, Object> resultMap = new LinkedHashMap<>(8); + try { + SystemInfo si = new SystemInfo(); + OperatingSystem os = si.getOperatingSystem(); + HardwareAbstractionLayer hal = si.getHardware(); + // 系统信息 + resultMap.put("sys", getSystemInfo(os)); + // cpu 信息 + resultMap.put("cpu", getCpuInfo(hal.getProcessor())); + // 内存信息 + resultMap.put("memory", getMemoryInfo(hal.getMemory())); + // 交换区信息 + resultMap.put("swap", getSwapInfo(hal.getMemory())); + // 磁盘 + resultMap.put("disk", getDiskInfo(os)); + resultMap.put("time", DateUtil.format(new Date(), "HH:mm:ss")); + } catch (Exception e) { + e.printStackTrace(); + } + return resultMap; + } + + /** + * 获取磁盘信息 + * @return / + */ + private Map<String,Object> getDiskInfo(OperatingSystem os) { + Map<String,Object> diskInfo = new LinkedHashMap<>(); + FileSystem fileSystem = os.getFileSystem(); + List<OSFileStore> fsArray = fileSystem.getFileStores(); + String osName = System.getProperty("os.name"); + long available = 0, total = 0; + for (OSFileStore fs : fsArray){ + // windows 需要将所有磁盘分区累加,linux 和 mac 直接累加会出现磁盘重复的问题,待修复 + if(osName.toLowerCase().startsWith(ElAdminConstant.WIN)) { + available += fs.getUsableSpace(); + total += fs.getTotalSpace(); + } else { + available = fs.getUsableSpace(); + total = fs.getTotalSpace(); + break; + } + } + long used = total - available; + diskInfo.put("total", total > 0 ? FileUtil.getSize(total) : "?"); + diskInfo.put("available", FileUtil.getSize(available)); + diskInfo.put("used", FileUtil.getSize(used)); + if(total != 0){ + diskInfo.put("usageRate", df.format(used/(double)total * 100)); + } else { + diskInfo.put("usageRate", 0); + } + return diskInfo; + } + + /** + * 获取交换区信息 + * @param memory / + * @return / + */ + private Map<String,Object> getSwapInfo(GlobalMemory memory) { + Map<String,Object> swapInfo = new LinkedHashMap<>(); + VirtualMemory virtualMemory = memory.getVirtualMemory(); + long total = virtualMemory.getSwapTotal(); + long used = virtualMemory.getSwapUsed(); + swapInfo.put("total", FormatUtil.formatBytes(total)); + swapInfo.put("used", FormatUtil.formatBytes(used)); + swapInfo.put("available", FormatUtil.formatBytes(total - used)); + if(used == 0){ + swapInfo.put("usageRate", 0); + } else { + swapInfo.put("usageRate", df.format(used/(double)total * 100)); + } + return swapInfo; + } + + /** + * 获取内存信息 + * @param memory / + * @return / + */ + private Map<String,Object> getMemoryInfo(GlobalMemory memory) { + Map<String,Object> memoryInfo = new LinkedHashMap<>(); + memoryInfo.put("total", FormatUtil.formatBytes(memory.getTotal())); + memoryInfo.put("available", FormatUtil.formatBytes(memory.getAvailable())); + memoryInfo.put("used", FormatUtil.formatBytes(memory.getTotal() - memory.getAvailable())); + memoryInfo.put("usageRate", df.format((memory.getTotal() - memory.getAvailable())/(double)memory.getTotal() * 100)); + return memoryInfo; + } + + /** + * 获取Cpu相关信息 + * @param processor / + * @return / + */ + private Map<String,Object> getCpuInfo(CentralProcessor processor) { + Map<String,Object> cpuInfo = new LinkedHashMap<>(); + cpuInfo.put("name", processor.getProcessorIdentifier().getName()); + cpuInfo.put("package", processor.getPhysicalPackageCount() + "个物理CPU"); + cpuInfo.put("core", processor.getPhysicalProcessorCount() + "个物理核心"); + cpuInfo.put("coreNumber", processor.getPhysicalProcessorCount()); + cpuInfo.put("logic", processor.getLogicalProcessorCount() + "个逻辑CPU"); + // CPU信息 + long[] prevTicks = processor.getSystemCpuLoadTicks(); + // 等待1秒... + Util.sleep(1000); + long[] ticks = processor.getSystemCpuLoadTicks(); + long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()]; + long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()]; + long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()]; + long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()]; + long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()]; + long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()]; + long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()]; + long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()]; + long totalCpu = user + nice + sys + idle + iowait + irq + softirq + steal; + cpuInfo.put("used", df.format(100d * user / totalCpu + 100d * sys / totalCpu)); + cpuInfo.put("idle", df.format(100d * idle / totalCpu)); + return cpuInfo; + } + + /** + * 获取系统相关信息,系统、运行天数、系统IP + * @param os / + * @return / + */ + private Map<String,Object> getSystemInfo(OperatingSystem os){ + Map<String,Object> systemInfo = new LinkedHashMap<>(); + // jvm 运行时间 + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + Date date = new Date(time); + // 计算项目运行时间 + String formatBetween = DateUtil.formatBetween(date, new Date(),BetweenFormater.Level.HOUR); + // 系统信息 + systemInfo.put("os", os.toString()); + systemInfo.put("day", formatBetween); + systemInfo.put("ip", StringUtils.getLocalIp()); + return systemInfo; + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/RoleServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/RoleServiceImpl.java new file mode 100644 index 0000000..4a54a8c --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/RoleServiceImpl.java @@ -0,0 +1,227 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import com.example.modules.system.domain.Menu; +import com.example.modules.system.domain.Role; +import com.example.modules.system.domain.User; +import com.example.modules.system.service.dto.RoleDto; +import com.example.modules.system.service.dto.RoleQueryCriteria; +import com.example.utils.*; +import lombok.RequiredArgsConstructor; +import com.example.exception.BadRequestException; +import com.example.modules.security.service.UserCacheClean; +import com.example.exception.EntityExistException; +import com.example.modules.system.repository.RoleRepository; +import com.example.modules.system.repository.UserRepository; +import com.example.modules.system.service.RoleService; +import com.example.modules.system.service.dto.RoleSmallDto; +import com.example.modules.system.service.dto.UserDto; +import com.example.modules.system.service.mapstruct.RoleMapper; +import com.example.modules.system.service.mapstruct.RoleSmallMapper; +import com.example.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * + * 2018-12-03 + */ +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "role") +public class RoleServiceImpl implements RoleService { + + private final RoleRepository roleRepository; + private final RoleMapper roleMapper; + private final RoleSmallMapper roleSmallMapper; + private final RedisUtils redisUtils; + private final UserRepository userRepository; + private final UserCacheClean userCacheClean; + + @Override + public List<RoleDto> queryAll() { + Sort sort = Sort.by(Sort.Direction.ASC, "level"); + return roleMapper.toDto(roleRepository.findAll(sort)); + } + + @Override + public List<RoleDto> queryAll(RoleQueryCriteria criteria) { + return roleMapper.toDto(roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder))); + } + + @Override + public Object queryAll(RoleQueryCriteria criteria, Pageable pageable) { + Page<Role> page = roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable); + return PageUtil.toPage(page.map(roleMapper::toDto)); + } + + @Override + @Cacheable(key = "'id:' + #p0") + @Transactional(rollbackFor = Exception.class) + public RoleDto findById(long id) { + Role role = roleRepository.findById(id).orElseGet(Role::new); + ValidationUtil.isNull(role.getId(), "Role", "id", id); + return roleMapper.toDto(role); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(Role resources) { + if (roleRepository.findByName(resources.getName()) != null) { + throw new EntityExistException(Role.class, "username", resources.getName()); + } + roleRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(Role resources) { + Role role = roleRepository.findById(resources.getId()).orElseGet(Role::new); + ValidationUtil.isNull(role.getId(), "Role", "id", resources.getId()); + + Role role1 = roleRepository.findByName(resources.getName()); + + if (role1 != null && !role1.getId().equals(role.getId())) { + throw new EntityExistException(Role.class, "username", resources.getName()); + } + role.setName(resources.getName()); + role.setDescription(resources.getDescription()); + role.setDataScope(resources.getDataScope()); + role.setDepts(resources.getDepts()); + role.setLevel(resources.getLevel()); + roleRepository.save(role); + // 更新相关缓存 + delCaches(role.getId(), null); + } + + @Override + public void updateMenu(Role resources, RoleDto roleDTO) { + Role role = roleMapper.toEntity(roleDTO); + List<User> users = userRepository.findByRoleId(role.getId()); + // 更新菜单 + role.setMenus(resources.getMenus()); + delCaches(resources.getId(), users); + roleRepository.save(role); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void untiedMenu(Long menuId) { + // 更新菜单 + roleRepository.untiedMenu(menuId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set<Long> ids) { + for (Long id : ids) { + // 更新相关缓存 + delCaches(id, null); + } + roleRepository.deleteAllByIdIn(ids); + } + + @Override + public List<RoleSmallDto> findByUsersId(Long id) { + return roleSmallMapper.toDto(new ArrayList<>(roleRepository.findByUserId(id))); + } + + @Override + public Integer findByRoles(Set<Role> roles) { + if (roles.size() == 0) { + return Integer.MAX_VALUE; + } + Set<RoleDto> roleDtos = new HashSet<>(); + for (Role role : roles) { + roleDtos.add(findById(role.getId())); + } + return Collections.min(roleDtos.stream().map(RoleDto::getLevel).collect(Collectors.toList())); + } + + @Override + @Cacheable(key = "'auth:' + #p0.id") + public List<GrantedAuthority> mapToGrantedAuthorities(UserDto user) { + Set<String> permissions = new HashSet<>(); + // 如果是管理员直接返回 + if (user.getIsAdmin()) { + permissions.add("admin"); + return permissions.stream().map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + } + Set<Role> roles = roleRepository.findByUserId(user.getId()); + permissions = roles.stream().flatMap(role -> role.getMenus().stream()) + .filter(menu -> StringUtils.isNotBlank(menu.getPermission())) + .map(Menu::getPermission).collect(Collectors.toSet()); + return permissions.stream().map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + } + + @Override + public void download(List<RoleDto> roles, HttpServletResponse response) throws IOException { + List<Map<String, Object>> list = new ArrayList<>(); + for (RoleDto role : roles) { + Map<String, Object> map = new LinkedHashMap<>(); + map.put("角色名称", role.getName()); + map.put("角色级别", role.getLevel()); + map.put("描述", role.getDescription()); + map.put("创建日期", role.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + @Override + public void verification(Set<Long> ids) { + if (userRepository.countByRoles(ids) > 0) { + throw new BadRequestException("所选角色存在用户关联,请解除关联再试!"); + } + } + + @Override + public List<Role> findInMenuId(List<Long> menuIds) { + return roleRepository.findInMenuId(menuIds); + } + + /** + * 清理缓存 + * @param id / + */ + public void delCaches(Long id, List<User> users) { + users = CollectionUtil.isEmpty(users) ? userRepository.findByRoleId(id) : users; + if (CollectionUtil.isNotEmpty(users)) { + users.forEach(item -> userCacheClean.cleanUserCache(item.getUsername())); + Set<Long> userIds = users.stream().map(User::getId).collect(Collectors.toSet()); + redisUtils.delByKeys(CacheKey.DATA_USER, userIds); + redisUtils.delByKeys(CacheKey.MENU_USER, userIds); + redisUtils.delByKeys(CacheKey.ROLE_AUTH, userIds); + } + redisUtils.del(CacheKey.ROLE_ID + id); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/UserServiceImpl.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..6b86b77 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/impl/UserServiceImpl.java @@ -0,0 +1,255 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.impl; + +import com.example.modules.system.domain.User; +import com.example.modules.system.service.UserService; +import com.example.modules.system.service.dto.JobSmallDto; +import com.example.modules.system.service.dto.UserQueryCriteria; +import com.example.utils.*; +import lombok.RequiredArgsConstructor; +import com.example.config.FileProperties; +import com.example.exception.BadRequestException; +import com.example.modules.security.service.OnlineUserService; +import com.example.modules.security.service.UserCacheClean; +import com.example.exception.EntityExistException; +import com.example.exception.EntityNotFoundException; +import com.example.modules.system.repository.UserRepository; +import com.example.modules.system.service.dto.RoleSmallDto; +import com.example.modules.system.service.dto.UserDto; +import com.example.modules.system.service.mapstruct.UserMapper; +import com.example.utils.*; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotBlank; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + + +@Service +@RequiredArgsConstructor +@CacheConfig(cacheNames = "user") +public class UserServiceImpl implements UserService { + + private final UserRepository userRepository; + private final UserMapper userMapper; + private final FileProperties properties; + private final RedisUtils redisUtils; + private final UserCacheClean userCacheClean; + private final OnlineUserService onlineUserService; + + @Override + public Object queryAll(UserQueryCriteria criteria, Pageable pageable) { + Page<User> page = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable); + return PageUtil.toPage(page.map(userMapper::toDto)); + } + + @Override + public List<UserDto> queryAll(UserQueryCriteria criteria) { + List<User> users = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)); + return userMapper.toDto(users); + } + + @Override + @Cacheable(key = "'id:' + #p0") + @Transactional(rollbackFor = Exception.class) + public UserDto findById(long id) { + User user = userRepository.findById(id).orElseGet(User::new); + ValidationUtil.isNull(user.getId(), "User", "id", id); + return userMapper.toDto(user); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void create(User resources) { + if (userRepository.findByUsername(resources.getUsername()) != null) { + throw new EntityExistException(User.class, "username", resources.getUsername()); + } + if (userRepository.findByEmail(resources.getEmail()) != null) { + throw new EntityExistException(User.class, "email", resources.getEmail()); + } + if (userRepository.findByPhone(resources.getPhone()) != null) { + throw new EntityExistException(User.class, "phone", resources.getPhone()); + } + userRepository.save(resources); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(User resources) throws Exception { + User user = userRepository.findById(resources.getId()).orElseGet(User::new); + ValidationUtil.isNull(user.getId(), "User", "id", resources.getId()); + User user1 = userRepository.findByUsername(resources.getUsername()); + User user2 = userRepository.findByEmail(resources.getEmail()); + User user3 = userRepository.findByPhone(resources.getPhone()); + if (user1 != null && !user.getId().equals(user1.getId())) { + throw new EntityExistException(User.class, "username", resources.getUsername()); + } + if (user2 != null && !user.getId().equals(user2.getId())) { + throw new EntityExistException(User.class, "email", resources.getEmail()); + } + if (user3 != null && !user.getId().equals(user3.getId())) { + throw new EntityExistException(User.class, "phone", resources.getPhone()); + } + // 如果用户的角色改变 + if (!resources.getRoles().equals(user.getRoles())) { + redisUtils.del(CacheKey.DATA_USER + resources.getId()); + redisUtils.del(CacheKey.MENU_USER + resources.getId()); + redisUtils.del(CacheKey.ROLE_AUTH + resources.getId()); + } + // 如果用户被禁用,则清除用户登录信息 + if(!resources.getEnabled()){ + onlineUserService.kickOutForUsername(resources.getUsername()); + } + user.setUsername(resources.getUsername()); + user.setEmail(resources.getEmail()); + user.setEnabled(resources.getEnabled()); + user.setRoles(resources.getRoles()); + user.setDept(resources.getDept()); + user.setJobs(resources.getJobs()); + user.setPhone(resources.getPhone()); + user.setNickName(resources.getNickName()); + user.setGender(resources.getGender()); + userRepository.save(user); + // 清除缓存 + delCaches(user.getId(), user.getUsername()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateCenter(User resources) { + User user = userRepository.findById(resources.getId()).orElseGet(User::new); + User user1 = userRepository.findByPhone(resources.getPhone()); + if (user1 != null && !user.getId().equals(user1.getId())) { + throw new EntityExistException(User.class, "phone", resources.getPhone()); + } + user.setNickName(resources.getNickName()); + user.setPhone(resources.getPhone()); + user.setGender(resources.getGender()); + userRepository.save(user); + // 清理缓存 + delCaches(user.getId(), user.getUsername()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Set<Long> ids) { + for (Long id : ids) { + // 清理缓存 + UserDto user = findById(id); + delCaches(user.getId(), user.getUsername()); + } + userRepository.deleteAllByIdIn(ids); + } + + @Override + public UserDto findByName(String userName) { + User user = userRepository.findByUsername(userName); + if (user == null) { + throw new EntityNotFoundException(User.class, "name", userName); + } else { + return userMapper.toDto(user); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePass(String username, String pass) { + userRepository.updatePass(username, pass, new Date()); + flushCache(username); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Map<String, String> updateAvatar(MultipartFile multipartFile) { + // 文件大小验证 + FileUtil.checkSize(properties.getAvatarMaxSize(), multipartFile.getSize()); + // 验证文件上传的格式 + String image = "gif jpg png jpeg"; + String fileType = FileUtil.getExtensionName(multipartFile.getOriginalFilename()); + if(fileType != null && !image.contains(fileType)){ + throw new BadRequestException("文件格式错误!, 仅支持 " + image +" 格式"); + } + User user = userRepository.findByUsername(SecurityUtils.getCurrentUsername()); + String oldPath = user.getAvatarPath(); + File file = FileUtil.upload(multipartFile, properties.getPath().getAvatar()); + user.setAvatarPath(Objects.requireNonNull(file).getPath()); + user.setAvatarName(file.getName()); + userRepository.save(user); + if (StringUtils.isNotBlank(oldPath)) { + FileUtil.del(oldPath); + } + @NotBlank String username = user.getUsername(); + flushCache(username); + return new HashMap<String, String>(1) {{ + put("avatar", file.getName()); + }}; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateEmail(String username, String email) { + userRepository.updateEmail(username, email); + flushCache(username); + } + + @Override + public void download(List<UserDto> queryAll, HttpServletResponse response) throws IOException { + List<Map<String, Object>> list = new ArrayList<>(); + for (UserDto userDTO : queryAll) { + List<String> roles = userDTO.getRoles().stream().map(RoleSmallDto::getName).collect(Collectors.toList()); + Map<String, Object> map = new LinkedHashMap<>(); + map.put("用户名", userDTO.getUsername()); + map.put("角色", roles); + map.put("部门", userDTO.getDept().getName()); + map.put("岗位", userDTO.getJobs().stream().map(JobSmallDto::getName).collect(Collectors.toList())); + map.put("邮箱", userDTO.getEmail()); + map.put("状态", userDTO.getEnabled() ? "启用" : "禁用"); + map.put("手机号码", userDTO.getPhone()); + map.put("修改密码的时间", userDTO.getPwdResetTime()); + map.put("创建日期", userDTO.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } + + /** + * 清理缓存 + * + * @param id / + */ + public void delCaches(Long id, String username) { + redisUtils.del(CacheKey.USER_ID + id); + flushCache(username); + } + + /** + * 清理 登陆时 用户缓存信息 + * + * @param username / + */ + private void flushCache(String username) { + userCacheClean.cleanUserCache(username); + } +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptMapper.java new file mode 100644 index 0000000..25de23f --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.Dept; +import com.example.modules.system.service.dto.DeptDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* +* 2019-03-25 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DeptMapper extends BaseMapper<DeptDto, Dept> { +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptSmallMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptSmallMapper.java new file mode 100644 index 0000000..01b7c65 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DeptSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.Dept; +import com.example.modules.system.service.dto.DeptSmallDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* +* 2019-03-25 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DeptSmallMapper extends BaseMapper<DeptSmallDto, Dept> { + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictDetailMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictDetailMapper.java new file mode 100644 index 0000000..42ad48c --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictDetailMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.DictDetail; +import com.example.modules.system.service.dto.DictDetailDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* +* 2019-04-10 +*/ +@Mapper(componentModel = "spring", uses = {DictSmallMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DictDetailMapper extends BaseMapper<DictDetailDto, DictDetail> { + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictMapper.java new file mode 100644 index 0000000..24b763e --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.Dict; +import com.example.modules.system.service.dto.DictDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* +* 2019-04-10 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DictMapper extends BaseMapper<DictDto, Dict> { + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictSmallMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictSmallMapper.java new file mode 100644 index 0000000..8f05535 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/DictSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.Dict; +import com.example.modules.system.service.dto.DictSmallDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* +* 2019-04-10 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface DictSmallMapper extends BaseMapper<DictSmallDto, Dict> { + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobMapper.java new file mode 100644 index 0000000..90be895 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.Job; +import com.example.modules.system.service.dto.JobDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* +* 2019-03-29 +*/ +@Mapper(componentModel = "spring",uses = {DeptMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface JobMapper extends BaseMapper<JobDto, Job> { +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobSmallMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobSmallMapper.java new file mode 100644 index 0000000..9a36c91 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/JobSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.Job; +import com.example.modules.system.service.dto.JobSmallDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* +* 2019-03-29 +*/ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface JobSmallMapper extends BaseMapper<JobSmallDto, Job> { + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/MenuMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/MenuMapper.java new file mode 100644 index 0000000..867cbf2 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/MenuMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.Menu; +import com.example.modules.system.service.dto.MenuDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * + * 2018-12-17 + */ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface MenuMapper extends BaseMapper<MenuDto, Menu> { +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleMapper.java new file mode 100644 index 0000000..929b14b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleMapper.java @@ -0,0 +1,28 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.Role; +import com.example.modules.system.service.dto.RoleDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + + +@Mapper(componentModel = "spring", uses = {MenuMapper.class, DeptMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface RoleMapper extends BaseMapper<RoleDto, Role> { + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleSmallMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleSmallMapper.java new file mode 100644 index 0000000..4d4ecff --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/RoleSmallMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.Role; +import com.example.modules.system.service.dto.RoleSmallDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * + * 2019-5-23 + */ +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface RoleSmallMapper extends BaseMapper<RoleSmallDto, Role> { + +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/UserMapper.java b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/UserMapper.java new file mode 100644 index 0000000..68a45dd --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/java/com/example/modules/system/service/mapstruct/UserMapper.java @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example.modules.system.service.mapstruct; + +import com.example.modules.system.domain.User; +import com.example.modules.system.service.dto.UserDto; +import com.example.base.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + + +@Mapper(componentModel = "spring",uses = {RoleMapper.class, DeptMapper.class, JobMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface UserMapper extends BaseMapper<UserDto, User> { +} diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/resources/banner.txt b/UI source code/dns-dev-2.0/dns-system/src/main/resources/banner.txt new file mode 100644 index 0000000..d0f401a --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + _ _ _ + | | | | (_) + ___| |______ __ _ __| |_ __ ___ _ _ __ + / _ | |______/ _` |/ _` | '_ ` _ \| | '_ \ + | __| | | (_| | (_| | | | | | | | | | | + \___|_| \__,_|\__,_|_| |_| |_|_|_| |_| + + :: Spring Boot :: (v2.1.0.RELEASE)
\ No newline at end of file diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/resources/config/application-dev.yml b/UI source code/dns-dev-2.0/dns-system/src/main/resources/config/application-dev.yml new file mode 100644 index 0000000..983bf6d --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/resources/config/application-dev.yml @@ -0,0 +1,118 @@ +#配置数据源 +spring: + datasource: + druid: + db-type: com.alibaba.druid.pool.DruidDataSource + driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy + url: jdbc:log4jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:eladmin}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false + username: ${DB_USER:root} + password: ${DB_PWD:root} + # 初始连接数 + initial-size: 5 + # 最小连接数 + min-idle: 15 + # 最大连接数 + max-active: 30 + # 超时时间(以秒数为单位) + remove-abandoned-timeout: 180 + # 获取连接超时时间 + max-wait: 3000 + # 连接有效性检测时间 + time-between-eviction-runs-millis: 60000 + # 连接在池中最小生存的时间 + min-evictable-idle-time-millis: 300000 + # 连接在池中最大生存的时间 + max-evictable-idle-time-millis: 900000 + # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 + test-while-idle: true + # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 + test-on-borrow: true + # 是否在归还到池中前进行检验 + test-on-return: false + # 检测连接是否有效 + validation-query: select 1 + # 配置监控统计 + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + reset-enable: false + filter: + stat: + enabled: true + # 记录慢SQL + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + +# 登录相关配置 +login: + # 登录缓存 + cache-enable: true + # 是否限制单用户登录 + single-login: false + # 验证码 + login-code: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic + # 登录图形验证码有效时间/分钟 + expiration: 2 + # 验证码高度 + width: 111 + # 验证码宽度 + height: 36 + # 内容长度 + length: 2 + # 字体名称,为空则使用默认字体 + font-name: + # 字体大小 + font-size: 25 + +#jwt +jwt: + header: Authorization + # 令牌前缀 + token-start-with: Bearer + # 必须使用最少88位的Base64对该令牌进行编码 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI= + # 令牌过期时间 此处单位/毫秒 ,默认4小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html + token-validity-in-seconds: 14400000 + # 在线用户key + online-key: online-token- + # 验证码 + code-key: code-key- + # token 续期检查时间范围(默认30分钟,单位毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期 + detect: 1800000 + # 续期时间范围,默认1小时,单位毫秒 + renew: 3600000 + +#是否允许生成代码,生产环境设置为false +generator: + enabled: true + +#是否开启 swagger-ui +swagger: + enabled: true + +# IP 本地解析 +ip: + local-parsing: true + +# 文件存储路径 +file: + mac: + path: ~/file/ + avatar: ~/avatar/ + linux: + path: /home/dns/file/ + avatar: /home/dns/avatar/ + windows: + path: C:\dns\file\ + avatar: C:\dns\avatar\ + # 文件大小 /M + maxSize: 100 + avatarMaxSize: 5 diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/resources/config/application-prod.yml b/UI source code/dns-dev-2.0/dns-system/src/main/resources/config/application-prod.yml new file mode 100644 index 0000000..8e1993f --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/resources/config/application-prod.yml @@ -0,0 +1,126 @@ +#配置数据源 +spring: + datasource: + druid: + db-type: com.alibaba.druid.pool.DruidDataSource + driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy + url: jdbc:log4jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:eladmin}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false + username: ${DB_USER:root} + password: ${DB_PWD:123456} + # 初始连接数 + initial-size: 5 + # 最小连接数 + min-idle: 15 + # 最大连接数 + max-active: 30 + # 获取连接超时时间 + max-wait: 5000 + # 连接有效性检测时间 + time-between-eviction-runs-millis: 60000 + # 连接在池中最小生存的时间 + min-evictable-idle-time-millis: 300000 + # 连接在池中最大生存的时间 + max-evictable-idle-time-millis: 900000 + # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 + test-while-idle: true + # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 + test-on-borrow: true + # 是否在归还到池中前进行检验 + test-on-return: false + # 检测连接是否有效 + validation-query: select 1 + # 配置监控统计 + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + # 控制台管理用户名和密码 + url-pattern: /druid/* + reset-enable: false + login-username: admin + login-password: 123456 + filter: + stat: + enabled: true + # 记录慢SQL + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + +# 登录相关配置 +login: + # 登录缓存 + cache-enable: true + # 是否限制单用户登录 + single-login: false + # 验证码 + login-code: + # 验证码类型配置 查看 LoginProperties 类 + code-type: arithmetic + # 登录图形验证码有效时间/分钟 + expiration: 2 + # 验证码高度 + width: 111 + # 验证码宽度 + height: 36 + # 内容长度 + length: 2 + # 字体名称,为空则使用默认字体,如遇到线上乱码,设置其他字体即可 + font-name: + # 字体大小 + font-size: 25 + +#jwt +jwt: + header: Authorization + # 令牌前缀 + token-start-with: Bearer + # 必须使用最少88位的Base64对该令牌进行编码 + base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI= + # 令牌过期时间 此处单位/毫秒 ,默认2小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html + token-validity-in-seconds: 7200000 + # 在线用户key + online-key: online-token- + # 验证码 + code-key: code-key- + # token 续期检查时间范围(默认30分钟,单位默认毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期 + detect: 1800000 + # 续期时间范围,默认 1小时,这里单位毫秒 + renew: 3600000 + +# IP 本地解析 +ip: + local-parsing: false + +#是否允许生成代码,生产环境设置为false +generator: + enabled: false + +#如果生产环境要开启swagger,需要配置请求地址 +#springfox: +# documentation: +# swagger: +# v2: +# host: # 接口域名或外网ip + +#是否开启 swagger-ui +swagger: + enabled: false + +# 文件存储路径 +file: + mac: + path: ~/file/ + avatar: ~/avatar/ + linux: + path: /home/dns/file/ + avatar: /home/dns/avatar/ + windows: + path: C:\dns\file\ + avatar: C:\dns\avatar\ + # 文件大小 /M + maxSize: 100 + avatarMaxSize: 5 diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/resources/config/application.yml b/UI source code/dns-dev-2.0/dns-system/src/main/resources/config/application.yml new file mode 100644 index 0000000..a43407b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/resources/config/application.yml @@ -0,0 +1,97 @@ +server: + port: 8888 + +spring: + freemarker: + check-template-location: false + profiles: + active: dev + jackson: + time-zone: GMT+8 + data: + redis: + repositories: + enabled: false +# pid: +# file: /自行指定位置/dns.pid + + #配置 Jpa + jpa: + hibernate: + ddl-auto: none + open-in-view: true + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL5InnoDBDialect + + redis: + #数据库索引 + database: ${REDIS_DB:0} + host: ${REDIS_HOST:127.0.0.1} + port: ${REDIS_PORT:6379} + password: ${REDIS_PWD:} + #连接超时时间 + timeout: 5000 + +task: + pool: + # 核心线程池大小 + core-pool-size: 10 + # 最大线程数 + max-pool-size: 30 + # 活跃时间 + keep-alive-seconds: 60 + # 队列容量 + queue-capacity: 50 + +#七牛云 +qiniu: + # 文件大小 /M + max-size: 15 + +#邮箱验证码有效时间/秒 +code: + expiration: 300 + +#密码加密传输,前端公钥加密,后端私钥解密 +rsa: + private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== + +# 内存用户缓存配置 +user-cache: + # 最小回收数(当缓存数量达到此值时进行回收) + min-evictable-size: 512 + # 最小回收间隔 + min-evictable-interval: 1800000 + # 最小存活时间 (ms) + min-idle-time: 3600000 + + +#mybatis +mybatis-plus: + mapper-locations: classpath*:/mapper/**/*.xml + #实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: com.example.modules.*.domain + global-config: + #数据库相关配置 + db-config: + #主键类型 AUTO:"数据库ID自增", INPUT:"用户输入ID", ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID"; + id-type: AUTO + #字段策略 IGNORED:"忽略判断",NOT_NULL:"非 NULL 判断"),NOT_EMPTY:"非空判断" + field-strategy: NOT_NULL + #驼峰下划线转换 + column-underline: true + logic-delete-value: 1 + logic-not-delete-value: 0 + banner: false + #原生配置 + configuration: + map-underscore-to-camel-case: true + cache-enabled: false + call-setters-on-nulls: true + jdbc-type-for-null: 'null' + +#showSql +logging: + level: + com.example.modules.system.mapper: debug diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/resources/generator.properties b/UI source code/dns-dev-2.0/dns-system/src/main/resources/generator.properties new file mode 100644 index 0000000..2ed9370 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/resources/generator.properties @@ -0,0 +1,27 @@ +#数据库类型转Java类型 +tinyint=Integer +smallint=Integer +mediumint=Integer +int=Integer +integer=Integer + +bigint=Long + +float=Float + +double=Double + +decimal=BigDecimal + +bit=Boolean + +char=String +varchar=String +tinytext=String +text=String +mediumtext=String +longtext=String + +date=Timestamp +datetime=Timestamp +timestamp=Timestamp
\ No newline at end of file diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/resources/log4jdbc.log4j2.properties b/UI source code/dns-dev-2.0/dns-system/src/main/resources/log4jdbc.log4j2.properties new file mode 100644 index 0000000..302525f --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/resources/log4jdbc.log4j2.properties @@ -0,0 +1,4 @@ +# If you use SLF4J. First, you need to tell log4jdbc-log4j2 that you want to use the SLF4J logger +log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator +log4jdbc.auto.load.popular.drivers=false +log4jdbc.drivers=com.mysql.cj.jdbc.Driver
\ No newline at end of file diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/resources/logback.xml b/UI source code/dns-dev-2.0/dns-system/src/main/resources/logback.xml new file mode 100644 index 0000000..8a399c4 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/resources/logback.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration scan="true" scanPeriod="30 seconds" debug="false"> + <contextName>DiamondV</contextName> + <property name="log.charset" value="utf-8" /> + <property name="log.pattern" value="%contextName- %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %msg%n" /> + + <!--输出到控制台--> + <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${log.pattern}</pattern> + <charset>${log.charset}</charset> + </encoder> + </appender> + + <!--普通日志输出到控制台--> + <root level="info"> + <appender-ref ref="console" /> + </root> + + <!--监控sql日志输出,如需监控 Sql 打印,请设置为 INFO --> + <logger name="jdbc.sqlonly" level="INFO" additivity="false"> + <appender-ref ref="console" /> + </logger> + + <logger name="jdbc.resultset" level="ERROR" additivity="false"> + <appender-ref ref="console" /> + </logger> + + <!-- 如想看到表格数据,将OFF改为INFO --> + <logger name="jdbc.resultsettable" level="OFF" additivity="false"> + <appender-ref ref="console" /> + </logger> + + <logger name="jdbc.connection" level="OFF" additivity="false"> + <appender-ref ref="console" /> + </logger> + + <logger name="jdbc.sqltiming" level="OFF" additivity="false"> + <appender-ref ref="console" /> + </logger> + + <logger name="jdbc.audit" level="OFF" additivity="false"> + <appender-ref ref="console" /> + </logger> +</configuration> diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/resources/mapper/dns/DnsDao.xml b/UI source code/dns-dev-2.0/dns-system/src/main/resources/mapper/dns/DnsDao.xml new file mode 100644 index 0000000..37d8a3b --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/resources/mapper/dns/DnsDao.xml @@ -0,0 +1,577 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="com.example.modules.dns.mapper.DnsDohDao"> + + <resultMap id="dohMap" type="com.example.modules.dns.domain.Result"> + <id property="id" column="id"/> + <id property="ip" column="ip"/> + <id property="host" column="host"/> + <id property="port" column="port"/> + <result property="path" column="path"/> + <result property="method" column="method"/> + <result property="connectType" column="connect_type"/> + <result property="statusCode" column="status_code"/> + <result property="repHeader" column="rep_header"/> + <result property="repBody" column="rep_body"/> + <result property="timestamp" column="timestamp"/> + <result property="component" column="component"/> + <result property="rounds" column="rounds"/> + <association property="ipInformation" columnPrefix="ii_" + javaType="com.example.modules.dns.domain.IpInformation"> + <result property="id" column="id"/> + <result property="ip" column="ip"/> + <result property="country" column="country"/> + <result property="province" column="province"/> + <result property="city" column="city"/> + <result property="district" column="district"/> + <result property="provider" column="provider"/> + <result property="isp" column="isp"/> + <result property="asnumber" column="asnumber"/> + <result property="timestamp" column="timestamp"/> + <result property="zipcode" column="zipcode"/> + <result property="timezone" column="timezone"/> + </association> + + <collection property="pathList" columnPrefix="da2_" ofType="String"> + <result property="pathList" column="path"/> + </collection> + + <collection property="componentList" columnPrefix="da2_" ofType="String"> + <result property="component" column="component"/> + </collection> + <collection property="ipCert" columnPrefix="ic_" ofType="com.example.modules.dns.domain.IpCert"> + <id property="id" column="id"/> + <result property="ip" column="ip"/> + <result property="port" column="port"/> + <result property="certificate" column="certificate"/> + <result property="ca" column="ca"/> + <result property="timestamp" column="timestamp"/> + </collection> + + <collection property="vulnerability" columnPrefix="v_" ofType="com.example.modules.dns.domain.Vulnerability"> + <id property="id" column="id"/> + <result property="component" column="component"/> + <result property="vulnerability" column="vulnerability"/> + <result property="timestamp" column="timestamp"/> + </collection> + + </resultMap> + + <select id="queryDohPage" resultMap="dohMap"> + SELECT da.id,da.ip,da.`host`,da.`port`,da.rounds,da.`timestamp` + ,GROUP_CONCAT(concat(da.method,'',da.path)) path + ,GROUP_CONCAT(distinct da.component) component + ,ii.country ii_country,ii.provider ii_provider,ii.city ii_city ,ii.asnumber ii_asnumber,ii.isp ii_isp, + ii.province ii_province,ii.zipcode ii_zipcode,ii.district ii_district, + v.`vulnerability` v_vulnerability + FROM (SELECT da.* FROM doh_attribute da + <where> + <if test="params.ip != null and params.ip != ''"> + da.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + AND da.`port` = #{params.port} + </if> + </where> + ) da + LEFT JOIN ip_information ii ON da.ip=ii.ip + LEFT JOIN `vulnerability` v ON v.`component` = da.`component` + + GROUP BY da.ip,da.port,da.host,da.rounds + order by da.`timestamp` desc + LIMIT #{params.n},#{params.m} + </select> + + <select id="dohProvinceCount" resultType="map"> + SELECT + COUNT(distinct da.ip) count,ii.`province` + FROM (SELECT DISTINCT ip from doh_attribute + <where> + <if test="params.ip != null and params.ip != ''"> + ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and port = #{params.port} + </if> + </where> + ) da + JOIN `ip_information` ii + ON da.ip = ii.ip AND ii.province IS NOT NULL AND ii.province !='' + GROUP BY ii.province + </select> + + <select id="dohChinaMapCount" resultType="map"> + SELECT ii.`province`, + COUNT(distinct da.ip) count + FROM `doh_attribute` da + JOIN `ip_information` ii + ON da.ip = ii.ip + where ii.country = '中国' + and da.`rounds` = (select MAX(rounds) FROM doh_attribute) + and ii.province IS NOT NULL + AND ii.province != '' + GROUP BY ii.province + + order by count desc + </select> + + <select id="dohCountryCount" resultType="map"> + SELECT ii.`country`, + COUNT(distinct da.ip) count + FROM `doh_attribute` da + JOIN `ip_information` ii + ON da.ip = ii.ip + where da.`rounds` = (SELECT DISTINCT MAX(rounds) FROM doh_attribute) + GROUP BY ii.country + order by count desc + </select> + + <select id="dohAndDo53ProvinceCount" resultType="map"> + SELECT province,SUM(count) count FROM ( + SELECT + ii.`province`,COUNT(distinct da.ip) count,da.ip + FROM `doh_attribute` da + JOIN `ip_information` ii + ON da.ip = ii.ip + where ii.province IS NOT NULL AND ii.province !='' + <if test="params.ip != null and params.ip != ''"> + and da.ip = #{params.ip} + </if> + GROUP BY ii.province + + UNION ALL + + SELECT + ii.`province`,COUNT(distinct s.ip) COUNT, s.ip + FROM `scan_result` s + JOIN `ip_information` ii + ON s.ip = ii.ip + where ii.province IS NOT NULL AND ii.province !='' + <if test="params.ip != null and params.ip != ''"> + and s.ip = #{params.ip} + </if> + GROUP BY ii.province + ) a1 + + GROUP BY a1.province + </select> + + <select id="dohProviderCount" resultType="map"> + SELECT + COUNT(ip_attr.ip) count,ii.`provider` + from + (SELECT DISTINCT ip from doh_attribute + <where> + <if test="params.ip != null and params.ip != ''"> + ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and port = #{params.port} + </if> + </where> + ) ip_attr + JOIN `ip_information` ii on ip_attr.ip = ii.ip AND ii.provider IS NOT NULL AND ii.provider !='' + + GROUP BY ii.provider + </select> + + <select id="dohAndDo53ProviderCount" resultType="map"> + + SELECT provider,SUM(COUNT) count FROM( + SELECT + ii.`provider`,COUNT(da.ip) COUNT,da.ip + FROM (SELECT id, ip from doh_attribute + <where> + <if test="params.ip != null and params.ip != ''"> + ip = #{params.ip} + </if> + </where> + ) da + JOIN `ip_information` ii ON da.ip = ii.ip + GROUP BY ii.provider + + UNION ALL + SELECT + ii.`provider`,COUNT(distinct s.ip) COUNT,s.ip + FROM `scan_result` s + JOIN `ip_information` ii ON s.ip = ii.ip + GROUP BY ii.provider + ) a1 + <where> + <if test="params.ip != null and params.ip != ''"> + a1.ip = #{params.ip} + </if> + </where> + GROUP BY a1.provider + HAVING provider IS NOT NULL AND provider !='' + </select> + + <select id="dohComponentCount" resultType="map"> + SELECT + da.component,COUNT(distinct da.ip) count + FROM (SELECT DISTINCT ip,component from doh_attribute + where + component IS NOT NULL AND component !='' + <if test="params.ip != null and params.ip != ''"> + and ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and port = #{params.port} + </if> + ) da + GROUP BY da.component + + </select> + + <select id="dohAndDo53ComponentCount" resultType="map"> + SELECT component,SUM(COUNT) count FROM ( + SELECT + da.component,COUNT(distinct da.ip) COUNT,da.ip + FROM `doh_attribute` da + <where> + + <if test="params.ip != null and params.ip != ''"> + da.ip = #{params.ip} + </if> + + </where> + GROUP BY da.component,da.ip + + UNION ALL + + SELECT + s.component,COUNT(distinct s.ip) COUNT ,s.ip + FROM `scan_result` s + GROUP BY s.component,s.ip) a1 + where component IS NOT NULL AND component !='' + <if test="params.ip != null and params.ip != ''"> + and a1.ip = #{params.ip} + </if> + + GROUP BY a1.component + + </select> + + <select id="dohServiceCategoryCount" resultType="map"> + <!--SELECT IFNULL(SUM(count),0) count FROM ( + SELECT da.ip,COUNT(distinct da.ip) count FROM `doh_attribute` da + <where> + <if test="params.ip != null and params.ip != ''"> + and da.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and da.port = #{params.port} + </if> + </where> + GROUP BY ip) a1--> + SELECT count(1) count from ( + SELECT distinct da.ip from `doh_attribute` da + <where> + <if test="params.ip != null and params.ip != ''"> + da.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and da.port = #{params.port} + </if> + </where> + ) a + + </select> + + <select id="dohResultTotalCount" resultType="int"> + SELECT COUNT(1) count FROM ( + SELECT ip,PORT,HOST,rounds + FROM `doh_attribute` da + <where> + <if test="params.ip != null and params.ip != ''"> + da.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and da.port = #{params.port} + </if> + </where> + GROUP BY ip,PORT,HOST,rounds + ) a1 + </select> + + <select id="dohVulnerabilityCount" resultType="map"> + SELECT vulnerability,COUNT(distinct ip) count FROM ( + SELECT da.ip,da.port,da.host,da.`component` + ,v.`vulnerability` + FROM `doh_attribute` da + JOIN `vulnerability` v ON v.`component` = da.`component` AND vulnerability IS NOT NULL AND vulnerability != '' + <where> + <if test="params.ip != null and params.ip != ''"> + da.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and da.port = #{params.port} + </if> + </where> + ) a1 + + GROUP BY a1.vulnerability + </select> + + <select id="dohAndDo53VulnerabilityCount" resultType="map"> + SELECT vulnerability,COUNT(distinct ip) count FROM ( + SELECT da.ip + ,v.`vulnerability` + FROM `doh_attribute` da + JOIN `vulnerability` v ON v.`component` = da.`component` + where vulnerability IS NOT NULL AND vulnerability !='' + <if test="params.ip != null and params.ip != ''"> + and ip = #{params.ip} + </if> + + UNION ALL + + SELECT s.ip + ,v.`vulnerability` + FROM `scan_result` s + JOIN `vulnerability` v ON v.`component` = s.`component` + where vulnerability IS NOT NULL AND vulnerability !='' + <if test="params.ip != null and params.ip != ''"> + and ip = #{params.ip} + </if> + ) a1 + + GROUP BY a1.vulnerability + </select> + + + <select id="dohPortCount" resultType="map"> + SELECT COUNT(ip) count,`port` FROM + (SELECT DISTINCT ip,port from doh_attribute + where `port` is not null AND `port` != '' + <if test="params.ip != null and params.ip != ''"> + and ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and port = #{params.port} + </if> + ) da + GROUP BY port + </select> + + + <select id="dohIpCount" resultType="int"> + SELECT COUNT(distinct da.ip) FROM doh_attribute da + <where> + <if test="params.ip != null and params.ip != ''"> + da.ip = #{params.ip} + </if> + </where> + </select> + <select id="getDohRepBody" resultMap="dohMap"> + select da.rep_body, da.rep_header + from doh_attribute da + where da.ip = #{ip} + AND da.port = #{port} + AND da.host = #{host} + AND da.rounds = #{rounds} + </select> + + <select id="selectDohInfoByUnion" resultMap="dohMap"> + SELECT da.*, + GROUP_CONCAT(concat(da.method, '', da.path)) path, + ii.country ii_country, + ii.provider ii_provider, + ii.city ii_city, + ii.asnumber ii_asnumber, + ii.isp ii_isp, + ii.province ii_province, + ii.zipcode ii_zipcode, + ii.district ii_district, + v.`vulnerability` v_vulnerability + from (select da.ip + from (select count(1), d.ip from doh_attribute d + <where> + <if test="params.ip != null and params.ip != ''"> + d.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and d.`port` = #{params.port} + </if> + </where> + group by d.ip) da + JOIN scan_result s on da.ip = s.ip) dip + join doh_attribute da on da.ip = dip.ip + left join ip_information ii on ii.ip = dip.ip + left join vulnerability v on v.component = da.component + + group by da.ip, da.host, da.`port`, da.rounds + order by da.`timestamp` desc + LIMIT #{params.offset},#{params.limit} + </select> + + <select id="selectDohCountByUnion" resultType="integer"> + select count(1) + from (SELECT da.id, da.ip, da.host, da.`port`, da.rounds + from (select da.ip + from (select count(1), d.ip from doh_attribute d + <where> + <if test="params.ip != null and params.ip != ''"> + d.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and d.`port` = #{params.port} + </if> + </where> + group by d.ip) da + JOIN scan_result s on da.ip = s.ip + ) dip + join doh_attribute da on da.ip = dip.ip + group by da.ip, da.host, da.`port`, da.rounds) total + + </select> + + <select id="countDohPortUnion" resultType="java.util.Map"> + + select count(distinct dh.ip) count ,dh.`port` + from (select distinct ip,`port` from doh_attribute + <where> + <if test="params.ip != null and params.ip != ''"> + ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and port = #{params.port} + </if> + </where> + ) dh + join scan_result sc on sc.ip = dh.ip + group by dh.`port` + having dh.`port` is not null AND dh.`port` != '' + + UNION ALL + + select count(distinct sc.ip) count,'53' as `port` + from (select distinct ip,`port` from doh_attribute da + <where> + <if test="params.ip != null and params.ip != ''"> + da.ip = #{params.ip} + </if> + </where> + ) dh + join scan_result sc on sc.ip = dh.ip + + </select> + + <select id="getDohAndDo53ProvinceCount" resultType="java.util.Map"> + SELECT + ii.`province`,COUNT(distinct s.ip) COUNT + FROM ( select sc.id,sc.ip from `scan_result` sc + <where> + <if test="params.ip != null and params.ip != ''"> + sc.ip = #{ip} + </if> + </where> + )s + join `doh_attribute` da on da.ip = s.ip + JOIN `ip_information` ii + ON s.ip = ii.ip + <where> + <if test="params.port != null and params.port != ''"> + da.`port` = #{params.port} + </if> + </where> + GROUP BY ii.province + having ii.province IS NOT NULL AND ii.province !='' + </select> + + <select id="getDohAndDo53ProviderCount" resultType="java.util.Map"> + SELECT + ii.`provider`,COUNT(distinct s.ip) COUNT + FROM ( select sc.id,sc.ip from `scan_result` sc + <where> + <if test="params.ip != null and params.ip != ''"> + sc.ip = #{ip} + </if> + </where> + )s + join `doh_attribute` da on da.ip = s.ip + JOIN `ip_information` ii + ON s.ip = ii.ip + <where> + <if test="params.port != null and params.port != ''"> + da.`port` = #{params.port} + </if> + </where> + GROUP BY ii.provider + having ii.provider IS NOT NULL AND ii.provider !='' + </select> + + <select id="getDohAndDo53ComponentCount" resultType="java.util.Map"> + SELECT + da.component component,count(distinct da.ip) count + FROM ( select count(1),d.ip,d.component from doh_attribute d + where d.component IS NOT NULL AND d.component !='' + <if test="params.ip != null and params.ip != ''"> + AND d.ip = #{ip} + </if> + ) da + JOIN scan_result s on da.ip = s.ip + <where> + <if test="params.port != null and params.port != ''"> + da.`port` = #{params.port} + </if> + </where> + GROUP BY da.component + having da.component IS NOT NULL AND da.component !='' + </select> + + <select id="getDohServiceCategoryCount" resultType="java.util.Map"> + SELECT count(DISTINCT da.ip) + from (select count(1),d.ip from doh_attribute d + <where> + <if test="params.ip != null and params.ip != ''"> + d.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and d.`port` = #{params.port} + </if> + </where> + group by d.ip) da + join scan_result sc on da.ip = sc.ip + </select> + <select id="getDohAndDo53VulnerabilityCount" resultType="java.util.Map"> + SELECT vulnerability, COUNT(distinct ip) count + FROM ( + select da.ip, dv.vulnerability + from (select count(1), d.ip, d.component + from doh_attribute d + where d.component is not null and d.component != '' + <if test="params.ip != null and params.ip != ''"> + and d.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and d.`port` = #{params.port} + </if> + group by d.ip, d.component) da + join scan_result sc on da.ip = sc.ip + join (select distinct v.vulnerability, d.component, d.ip from doh_attribute d + JOIN `vulnerability` v ON v.`component` = d.`component`) dv + on da.ip = dv.ip + where dv.vulnerability is not null and dv.vulnerability != '' + + union all + + select s.ip, dv.vulnerability + from (select count(1), d.ip from doh_attribute d + group by d.ip + ) da + join scan_result s on da.ip = s.ip + join (select distinct v.vulnerability, sc.component, sc.ip + from scan_result sc + JOIN `vulnerability` v ON v.`component` = sc.`component`) dv + on s.ip = dv.ip + where dv.vulnerability is not null and dv.vulnerability != '' + <if test="params.ip != null and params.ip != ''"> + and s.ip = #{params.ip} + </if> + ) a1 + GROUP BY a1.vulnerability + </select> + +</mapper> diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/resources/mapper/dns/DnsDo53Dao.xml b/UI source code/dns-dev-2.0/dns-system/src/main/resources/mapper/dns/DnsDo53Dao.xml new file mode 100644 index 0000000..849fc64 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/resources/mapper/dns/DnsDo53Dao.xml @@ -0,0 +1,400 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="com.example.modules.dns.mapper.DnsDo53Dao"> + + <resultMap id="do53Map" type="com.example.modules.dns.domain.Result"> + <id property="id" column="id"/> + <result property="ip" column="ip"/> + <result property="flags" column="flags"/> + <result property="opcode" column="opcode"/> + <result property="qr" column="qr"/> + <result property="aa" column="aa"/> + <result property="ra" column="ra"/> + <result property="rcode" column="rcode"/> + <result property="queryName" column="queryName"/> + <result property="queryResponse" column="query_response"/> + <result property="component" column="component"/> + <result property="scanType" column="scanType"/> + <result property="timestamp" column="time"/> + <result property="dnsType" column="dnsType"/> + <result property="epoch" column="epoch"/> + + <association property="ipInformation" columnPrefix="ii_" + javaType="com.example.modules.dns.domain.IpInformation"> + <result property="id" column="id"/> + <result property="ip" column="ip"/> + <result property="country" column="country"/> + <result property="province" column="province"/> + <result property="city" column="city"/> + <result property="district" column="district"/> + <result property="provider" column="provider"/> + <result property="isp" column="isp"/> + <result property="asnumber" column="asnumber"/> + <result property="timestamp" column="timestamp"/> + <result property="zipcode" column="zipcode"/> + <result property="timezone" column="timezone"/> + </association> + <collection property="componentList" ofType="String"> + <result property="component" column="component"/> + </collection> + + <collection property="vulnerability" columnPrefix="v_" ofType="com.example.modules.dns.domain.Vulnerability"> + <id property="id" column="id"/> + <result property="component" column="component"/> + <result property="vulnerability" column="vulnerability"/> + <result property="timestamp" column="timestamp"/> + </collection> + + + </resultMap> + + <select id="queryDo53Page" resultMap="do53Map"> + SELECT s.*, + ii.country ii_country,ii.provider ii_provider, + ii.city ii_city ,ii.asnumber ii_asnumber,ii.isp ii_isp, + ii.province ii_province,ii.zipcode ii_zipcode,ii.district ii_district, + dt.type dnsType,v.`vulnerability` v_vulnerability + FROM (select s.* from scan_result s + <where> + <if test="params.ip != null and params.ip != ''"> + s.ip = #{params.ip} + </if> + </where> + order by s.time desc + LIMIT #{params.n},#{params.m} + ) s + LEFT JOIN ip_information ii ON ii.ip = s.ip + LEFT JOIN dns_type dt ON dt.ip = s.ip AND dt.`epoch` = s.`epoch` + LEFT JOIN `vulnerability` v ON v.`component` = s.`component` + + + </select> + + <select id="do53IpCount" resultType="int"> + SELECT COUNT(distinct ip) FROM `scan_result` + <where> + <if test="params.ip != null and params.ip != ''"> + ip = #{params.ip} + </if> + </where> + + </select> + + <select id="do53ServiceCategoryCount" resultType="map"> + SELECT TYPE,COUNT(distinct ip) count FROM ( + SELECT s.ip,dt.type FROM `scan_result` s + JOIN `dns_type` dt ON s.ip=dt.ip + where type IS NOT NULL AND type !='' + <if test="params.ip != null and params.ip != ''"> + and s.ip = #{params.ip} + </if> + <if test="params.dnsType != null and params.dnsType != ''"> + and dt.type = #{params.dnsType} + </if> + ) a1 + GROUP BY a1.type + </select> + + <select id="do53ProvinceCount" resultType="map"> + SELECT + ii.`province`,COUNT(distinct s.ip) count + FROM `scan_result` s + JOIN `ip_information` ii + ON s.ip = ii.ip AND ii.province IS NOT NULL AND ii.province !='' + <where> + <if test="params.ip != null and params.ip != ''"> + and s.ip = #{params.ip} + </if> + </where> + GROUP BY ii.province + </select> + + <select id="do53CountryCount" resultType="map"> + SELECT ii.`country`, + COUNT(s.ip) count + FROM `scan_result` s + JOIN `ip_information` ii + ON s.ip = ii.ip + GROUP BY ii.country + </select> + + <select id="do53CountryMapCount" resultType="map"> + SELECT ii.`country`, + COUNT(ii.`country`) count, + dt.type + FROM `dns_type` dt + JOIN `ip_information` ii ON dt.ip = ii.ip + WHERE dt.epoch = (SELECT MAX(epoch) FROM `dns_type`) + GROUP BY ii.`country`, dt.`type` + order by count desc + </select> + + <select id="do53WorldMapCount" resultType="map"> + SELECT ii.`country`, + COUNT(ii.`country`) count + FROM `dns_type` dt + JOIN `ip_information` ii ON dt.ip = ii.ip + WHERE dt.epoch = (SELECT MAX(epoch) FROM `dns_type`) + GROUP BY ii.`country` + order by count desc + </select> + + <select id="do53ChinaMapCount" resultType="map"> + SELECT ii.`province`, + COUNT(ii.`province`) count + FROM `dns_type` dt + JOIN `ip_information` ii ON dt.ip = ii.ip + WHERE ii.country = '中国' + and dt.epoch = (SELECT MAX(epoch) FROM `dns_type`) + GROUP BY ii.`province` + order by count desc + </select> + + <select id="do53ProviderCount" resultType="map"> + SELECT + ii.`provider`,COUNT(s.ip) count + FROM `scan_result` s + JOIN `ip_information` ii + ON s.ip = ii.ip AND provider IS NOT NULL AND provider !='' + <where> + <if test="params.ip != null and params.ip != ''"> + s.ip = #{params.ip} + </if> + </where> + GROUP BY ii.provider + </select> + + + <select id="do53ComponentCount" resultType="map"> + SELECT + s.component,COUNT(distinct s.ip) count + FROM `scan_result` s + where + component IS NOT NULL AND component !='' + <if test="params.ip != null and params.ip != ''"> + and s.ip = #{params.ip} + </if> + GROUP BY s.component + </select> + + <select id="do53VulnerabilityCount" resultType="map"> + + SELECT vulnerability,COUNT(ip) count FROM ( + SELECT s.ip + ,v.`vulnerability` + FROM `scan_result` s + JOIN `vulnerability` v ON v.`component` = s.`component` + where vulnerability IS NOT NULL AND vulnerability !='' + <if test="params.ip != null and params.ip != ''"> + and s.ip = #{params.ip} + </if> + ) a1 + GROUP BY a1.vulnerability + </select> + + <select id="pageCount" resultType="java.lang.Integer"> + select count(1) from scan_result s + <where> + <if test="params.ip != null and params.ip != ''"> + s.ip = #{params.ip} + </if> + </where> + </select> + + <select id="queryOpenRdns" resultType="result"> + select sc.*, + dt.type dnsType, + ii.country ii_country,ii.provider ii_provider,ii.city ii_city ,ii.asnumber ii_asnumber,ii.isp ii_isp, + ii.province ii_province,ii.zipcode ii_zipcode,ii.district ii_district, + v.`vulnerability` v_vulnerability + from + ( + select sc.* from + scan_result sc join (select ip,epoch from dns_type where type = 1) dt on dt.ip = sc.ip and dt.epoch = sc.epoch + <where> + <if test="params.ip != null and params.ip != ''"> + sc.ip = #{params.ip} + </if> + </where> + order by sc.epoch desc,sc.`time` desc LIMIT #{params.offset},#{params.limit} + ) sc + + left join ip_information ii on sc.ip = ii.ip + left join vulnerability v on sc.component = v.component + </select> + + <select id="getCountByDnsType" resultType="java.lang.Integer"> + select count(1) from + (select id,ip,epoch from scan_result sr + <where> + <if test="params.ip != null and params.ip != ''"> + sr.ip = #{params.ip} + </if> + </where> + ) sc + join ( select d.id,d.ip,d.epoch from dns_type d where d.type = #{dnsType}) dt + on dt.ip = sc.ip AND dt.epoch = sc.epoch + + + </select> + + <select id="getIndependentIpNum" resultType="java.lang.Integer"> + select count(distinct sc.ip) + from ( select id,ip,epoch from scan_result sr + <where> + <if test="params.ip != null and params.ip != ''"> + ip = #{params.ip} + </if> + </where> + ) sc + join (select ip, epoch from dns_type d where d.type = #{dnsType}) + dt on dt.ip = sc.ip and dt.epoch = sc.epoch + + </select> + + <select id="selectScanResultCountByUnion" resultType="java.lang.Integer"> + select count(1) count + from ( + select da.ip + from (select count(1), d.ip from doh_attribute d + <where> + <if test="params.ip != null and params.ip != ''"> + d.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and d.`port` = #{params.port} + </if> + </where> + group by d.ip) da + JOIN scan_result s on da.ip = s.ip + ) dip + join scan_result sc on sc.ip = dip.ip + </select> + + <select id="selectScanResultByUnion" resultMap="do53Map"> + SELECT sc.*, + ii.country ii_country, ii.provider ii_provider, + ii.city ii_city, ii.asnumber ii_asnumber, ii.isp ii_isp, + ii.province ii_province,ii.zipcode ii_zipcode, + ii.district ii_district, + dt.type dnsType, v.`vulnerability` v_vulnerability + from ( + select da.ip + from (select count(1), d.ip from doh_attribute d + <where> + <if test="params.ip != null and params.ip != ''"> + d.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and d.`port` = #{params.port} + </if> + </where> + group by d.ip) da + JOIN scan_result s on da.ip = s.ip + ) dip + + join scan_result sc on sc.ip = dip.ip + left join ip_information ii on ii.ip = dip.ip + left join vulnerability v on v.component = sc.component + left join dns_type dt ON dt.ip = sc.ip AND dt.`epoch` = sc.`epoch` + order by sc.`time` desc + LIMIT #{params.offset},#{params.limit} + </select> + + <select id="getDohAndDo53SrvCategoryCount" resultType="java.util.Map"> + SELECT dt.type, COUNT(distinct da.ip) count + FROM (select count(1),d.ip from doh_attribute d + <where> + <if test="params.ip != null and params.ip != ''"> + d.ip = #{params.ip} + </if> + <if test="params.port != null and params.port != ''"> + and d.`port` = #{params.port} + </if> + </where> + group by d.ip + ) da + JOIN scan_result s on da.ip = s.ip + JOIN `dns_type` dt ON da.ip = dt.ip and dt.type > 0 + + GROUP BY dt.type + </select> + + <select id="getDo53ProvinceCountByDnsType" resultType="java.util.Map"> + select s.`province`,COUNT(distinct s.ip) count from + (SELECT s.ip,ii.province FROM `scan_result` s + JOIN `ip_information` ii ON s.ip = ii.ip + where ii.province IS NOT NULL AND ii.province !='' + <if test="params.ip != null and params.ip != ''"> + AND s.ip = #{params.ip} + </if> + ) s + join dns_type dt on s.ip = dt.ip + where dt.type = #{dnsType} + GROUP BY s.province + </select> + + <select id="getDo53ProviderCountByDnsType" resultType="java.util.Map"> + SELECT + s.`provider`,COUNT(distinct s.ip) count + FROM ( SELECT ii.`provider`,s.ip + FROM `scan_result` s + JOIN `ip_information` ii + ON s.ip = ii.ip AND provider IS NOT NULL AND provider !='' + <where> + <if test="params.ip != null and params.ip != ''"> + s.ip = #{params.ip} + </if> + </where> + ) s + JOIN dns_type dt on dt.ip = s.ip + <if test="dnsType != null and dnsType != ''"> + AND dt.type = #{dnsType} + </if> + GROUP BY s.provider + </select> + + <select id="getDo53ComponentCountByDnsType" resultType="java.util.Map"> + select s.component,COUNT(distinct s.ip) count + from ( + SELECT s.component, s.ip FROM `scan_result` s + where + component IS NOT NULL AND component !='' + <if test="params.ip != null and params.ip != ''"> + and s.ip = #{params.ip} + </if> + ) s + JOIN (SELECT ip from dns_type where type = #{dnsType}) dt on s.ip = dt.ip + GROUP BY s.component + </select> + + <select id="getDo53SrvCategoryCountByDnsType" resultType="java.lang.Integer"> + SELECT COUNT(a1.ip) count FROM ( + SELECT s.ip,dt.type FROM `scan_result` s + JOIN `dns_type` dt ON s.ip=dt.ip + where dt.type = #{dnsType} + <if test="params.ip != null and params.ip != ''"> + and s.ip = #{params.ip} + </if> + ) a1 + GROUP BY a1.type + </select> + + <select id="getDo53VulnerabCountByDnsType" resultType="java.util.Map"> + SELECT vulnerability,COUNT(a1.ip) count FROM ( + SELECT s.ip + ,v.`vulnerability` + FROM `scan_result` s + JOIN `vulnerability` v ON v.`component` = s.`component` + where vulnerability IS NOT NULL AND vulnerability !='' + <if test="params.ip != null and params.ip != ''"> + and s.ip = #{params.ip} + </if> + ) a1 + JOIN dns_type dt on a1.ip = dt.ip and dt.type = #{dnsType} + GROUP BY a1.vulnerability + </select> + + +</mapper> diff --git a/UI source code/dns-dev-2.0/dns-system/src/main/resources/mapper/dns/IpInformationDao.xml b/UI source code/dns-dev-2.0/dns-system/src/main/resources/mapper/dns/IpInformationDao.xml new file mode 100644 index 0000000..f4a0047 --- /dev/null +++ b/UI source code/dns-dev-2.0/dns-system/src/main/resources/mapper/dns/IpInformationDao.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + +<mapper namespace="com.example.modules.dns.mapper.IpInformationDao"> + + <resultMap id="ipMap" type="com.example.modules.dns.domain.IpInformation"> + <id property="id" column="id"/> + <id property="ip" column="ip"/> + <result property="country" column="country"/> + <result property="province" column="province"/> + <result property="city" column="city"/> + <result property="district" column="district"/> + <result property="provider" column="provider"/> + <result property="isp" column="isp"/> + <result property="asnumber" column="asnumber"/> + <result property="timestamp" column="timestamp"/> + <result property="zipcode" column="zipcode"/> + <result property="timezone" column="timezone"/> + + <association property="dnsType" columnPrefix="dt_" javaType="com.example.modules.dns.domain.DnsType"> + <id property="id" column="id"/> + <id property="ip" column="ip"/> + <result property="type" column="type"/> + </association> + + <collection property="ipCert" columnPrefix="ic_" ofType="com.example.modules.dns.domain.IpCert"> + <id property="id" column="id"/> + <id property="ip" column="ip"/> + <result property="port" column="port"/> + <result property="certificate" column="certificate"/> + <result property="ca" column="ca"/> + <result property="timestamp" column="timestamp"/> + </collection> + + <collection property="dohAttribute" columnPrefix="da_" ofType="com.example.modules.dns.domain.DohAttribute"> + <id property="ip" column="ip"/> + <result property="host" column="host"/> + <result property="port" column="port"/> + <result property="path" column="path"/> + <result property="method" column="method"/> + <result property="connectType" column="connect_type"/> + <result property="statusCode" column="status_code"/> + <result property="repHeader" column="rep_header"/> + <result property="repBody" column="rep_body"/> + <result property="timestamp" column="timestamp"/> + <result property="component" column="component"/> + </collection> + + </resultMap> + + + + <select id="queryIpPage" resultMap="ipMap"> + SELECT ii.* +-- ,ic.certificate ic_certificate ,ic.ca ic_ca + ,da.host da_host , da.rep_body da_rep_body , da.status_code da_status_code ,da.component da_component,da.path da_path + FROM `ip_information` ii +-- LEFT JOIN `ip_cert` ic ON ii.ip = ic.ip + left join doh_attribute da on ii.ip = da.ip + + <where> + <if test="params.ip != null and params.ip != ''"> + and ii.ip = #{params.ip} + </if> + </where> + + </select> + <select id="getIpInfoByFwd" resultType="ipInformation"> + select ii.* from ip_information ii + join (SELECT fd.upstream from forward_dns fd where fd.forwarder = #{ip} + <if test="epoch != '' and epoch != null "> + and fd.epoch = #{epoch} + </if> + ) fw + on fw.upstream = ii.ip + </select> + +</mapper> diff --git a/UI source code/dns-dev-2.0/pom.xml b/UI source code/dns-dev-2.0/pom.xml new file mode 100644 index 0000000..84d1b52 --- /dev/null +++ b/UI source code/dns-dev-2.0/pom.xml @@ -0,0 +1,266 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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.example</groupId> + <artifactId>dns</artifactId> + <packaging>pom</packaging> + <version>2.6</version> + + <modules> + <module>dns-common</module> + <module>dns-logging</module> + <module>dns-system</module> + </modules> + + <name>DNS测绘</name> + <url>https://el-admin.vip</url> + + <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>2.2.10.RELEASE</version> + </parent> + + <properties> + <log4j2.version>2.17.0</log4j2.version> + <logback.version>1.2.9</logback.version> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <java.version>1.8</java.version> + <log4jdbc.version>1.16</log4jdbc.version> + <swagger.version>2.9.2</swagger.version> + <fastjson.version>1.2.70</fastjson.version> + <druid.version>1.1.24</druid.version> + <commons-pool2.version>2.5.0</commons-pool2.version> + <mapstruct.version>1.3.1.Final</mapstruct.version> + <mybatisplus.version>3.0.7.1</mybatisplus.version> + </properties> + + <dependencies> +<!-- mybatis-plus--> + <dependency> + <groupId>com.baomidou</groupId> + <artifactId>mybatis-plus-boot-starter</artifactId> + <version>${mybatisplus.version}</version> + <exclusions> + <exclusion> + <groupId>com.baomidou</groupId> + <artifactId>mybatis-plus-generator</artifactId> + </exclusion> + </exclusions> + </dependency> + <!--Spring boot 核心--> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-jpa</artifactId> + </dependency> + + <!--Spring boot Web容器--> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + + </dependency> + + <!--Spring boot 测试--> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + + <!--Spring boot 安全框架--> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + + <!-- spring boot 缓存 --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-cache</artifactId> + </dependency> + + <!--Spring boot Redis--> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-redis</artifactId> + </dependency> + + <!--spring boot 集成redis所需common-pool2--> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-pool2</artifactId> + <version>${commons-pool2.version}</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + + <!--监控sql日志--> + <dependency> + <groupId>org.bgee.log4jdbc-log4j2</groupId> + <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId> + <version>${log4jdbc.version}</version> + </dependency> + + <!-- Swagger UI 相关 --> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger2</artifactId> + <version>${swagger.version}</version> + <exclusions> + <exclusion> + <groupId>io.swagger</groupId> + <artifactId>swagger-annotations</artifactId> + </exclusion> + <exclusion> + <groupId>io.swagger</groupId> + <artifactId>swagger-models</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>${swagger.version}</version> + </dependency> + <dependency> + <groupId>io.swagger</groupId> + <artifactId>swagger-annotations</artifactId> + <version>1.5.21</version> + </dependency> + <dependency> + <groupId>io.swagger</groupId> + <artifactId>swagger-models</artifactId> + <version>1.5.21</version> + </dependency> + + <!--Mysql依赖包--> + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + <scope>runtime</scope> + </dependency> + + <!-- druid数据源驱动 --> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>druid-spring-boot-starter</artifactId> + <version>${druid.version}</version> + </dependency> + + <!-- ip2region IP库 --> + <dependency> + <groupId>net.dreamlu</groupId> + <artifactId>mica-ip2region</artifactId> + <version>2.5.6</version> + </dependency> + + + <!--lombok插件--> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <optional>true</optional> + </dependency> + + <!-- excel工具 --> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi</artifactId> + <version>3.17</version> + </dependency> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi-ooxml</artifactId> + <version>3.17</version> + </dependency> + <dependency> + <groupId>xerces</groupId> + <artifactId>xercesImpl</artifactId> + <version>2.12.2</version> + </dependency> + + <!-- fastjson --> + <dependency> + <groupId>com.alibaba</groupId> + <artifactId>fastjson</artifactId> + <version>${fastjson.version}</version> + </dependency> + + <!--mapStruct依赖--> + <dependency> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct</artifactId> + <version>${mapstruct.version}</version> + </dependency> + <dependency> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct-processor</artifactId> + <version>${mapstruct.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>javax.inject</groupId> + <artifactId>javax.inject</artifactId> + <version>1</version> + </dependency> + + <!-- Java图形验证码 --> + <dependency> + <groupId>com.github.whvcse</groupId> + <artifactId>easy-captcha</artifactId> + <version>1.6.2</version> + </dependency> + + <!-- 解析客户端操作系统、浏览器信息 --> + <dependency> + <groupId>nl.basjes.parse.useragent</groupId> + <artifactId>yauaa</artifactId> + <version>5.23</version> + </dependency> + </dependencies> + + <build> + <plugins> + <!-- 打包时跳过测试 --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + </plugins> + </build> + + <repositories> + <repository> + <id>public</id> + <name>aliyun nexus</name> + <url>http://maven.aliyun.com/nexus/content/groups/public/</url> + <releases> + <enabled>true</enabled> + </releases> + </repository> + </repositories> + + <pluginRepositories> + <pluginRepository> + <id>public</id> + <name>aliyun nexus</name> + <url>http://maven.aliyun.com/nexus/content/groups/public/</url> + <releases> + <enabled>true</enabled> + </releases> + <snapshots> + <enabled>false</enabled> + </snapshots> + </pluginRepository> + </pluginRepositories> +</project> diff --git a/UI source code/dns-dev-2.0/sql/DiamondV.sql b/UI source code/dns-dev-2.0/sql/DiamondV.sql new file mode 100644 index 0000000..cfb1dea --- /dev/null +++ b/UI source code/dns-dev-2.0/sql/DiamondV.sql @@ -0,0 +1,1059 @@ +/* +SQLyog Ultimate v13.1.1 (64 bit) +MySQL - 5.7.30-log : Database - eladmin +********************************************************************* +*/ + +/*!40101 SET NAMES utf8 */; + +/*!40101 SET SQL_MODE=''*/; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +CREATE DATABASE /*!32312 IF NOT EXISTS*/`diamondv` /*!40100 DEFAULT CHARACTER SET utf8 */; + +USE `diamondv`; + + +/*Table structure for table `code_column_config` */ + +DROP TABLE IF EXISTS `code_column_config`; + +CREATE TABLE `code_column_config` ( + `column_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `table_name` varchar(255) DEFAULT NULL, + `column_name` varchar(255) DEFAULT NULL, + `column_type` varchar(255) DEFAULT NULL, + `dict_name` varchar(255) DEFAULT NULL, + `extra` varchar(255) DEFAULT NULL, + `form_show` bit(1) DEFAULT NULL, + `form_type` varchar(255) DEFAULT NULL, + `key_type` varchar(255) DEFAULT NULL, + `list_show` bit(1) DEFAULT NULL, + `not_null` bit(1) DEFAULT NULL, + `query_type` varchar(255) DEFAULT NULL, + `remark` varchar(255) DEFAULT NULL, + `date_annotation` varchar(255) DEFAULT NULL, + PRIMARY KEY (`column_id`) USING BTREE, + KEY `idx_table_name` (`table_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='代码生成字段信息存储'; + +/*Data for the table `code_column_config` */ + +/*Table structure for table `code_gen_config` */ + +DROP TABLE IF EXISTS `code_gen_config`; + +CREATE TABLE `code_gen_config` ( + `config_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `table_name` varchar(255) DEFAULT NULL COMMENT '表名', + `author` varchar(255) DEFAULT NULL COMMENT '作者', + `cover` bit(1) DEFAULT NULL COMMENT '是否覆盖', + `module_name` varchar(255) DEFAULT NULL COMMENT '模块名称', + `pack` varchar(255) DEFAULT NULL COMMENT '至于哪个包下', + `path` varchar(255) DEFAULT NULL COMMENT '前端代码生成的路径', + `api_path` varchar(255) DEFAULT NULL COMMENT '前端Api文件路径', + `prefix` varchar(255) DEFAULT NULL COMMENT '表前缀', + `api_alias` varchar(255) DEFAULT NULL COMMENT '接口名称', + PRIMARY KEY (`config_id`) USING BTREE, + KEY `idx_table_name` (`table_name`(100)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='代码生成器配置'; + +/*Data for the table `code_gen_config` */ + +/*Table structure for table `component` */ + +DROP TABLE IF EXISTS `component`; + +CREATE TABLE `component` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `component` varchar(128) DEFAULT NULL, + `vulnerability` varchar(128) DEFAULT NULL, + `timestamp` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +/*Data for the table `component` */ + +/*Table structure for table `dns_type` */ + +DROP TABLE IF EXISTS `dns_type`; + +CREATE TABLE `dns_type` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ip` varchar(128) DEFAULT NULL, + `type` tinyint(4) DEFAULT NULL, + `epoch` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; + +/*Data for the table `dns_type` */ + +insert into `dns_type`(`id`,`ip`,`type`,`epoch`) values +(1,'1.1.1.1',1,2), +(2,'2.2.2.2',2,2), +(3,'3.3.3.3',3,2), +(4,'4.4.4.4',4,2), +(5,'5.5.5.5',5,2), +(6,'6.6.6.6',1,2), +(7,'7.7.7.7',1,2), +(8,'1.1.1.1',3,1), +(9,'2.2.2.2',5,1); + +/*Table structure for table `doh_attribute` */ + +DROP TABLE IF EXISTS `doh_attribute`; + +CREATE TABLE `doh_attribute` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ip` varchar(128) DEFAULT NULL, + `port` int(11) DEFAULT NULL, + `host` varchar(128) DEFAULT NULL, + `path` varchar(128) DEFAULT NULL, + `method` varchar(4) DEFAULT NULL, + `connect_type` int(11) DEFAULT NULL, + `status_code` int(11) DEFAULT NULL, + `rep_header` varchar(2048) DEFAULT NULL, + `rep_body` varchar(1024) DEFAULT NULL, + `timestamp` datetime DEFAULT NULL, + `component` varchar(128) DEFAULT NULL, + `rounds` tinyint(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_ip` (`ip`) +) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8; + +/*Data for the table `doh_attribute` */ + +insert into `doh_attribute`(`id`,`ip`,`port`,`host`,`path`,`method`,`connect_type`,`status_code`,`rep_header`,`rep_body`,`timestamp`,`component`,`rounds`) values +(1,'1.1.1.1',8443,'192.168.32.46','/test1','post',1,200,'{head1}','{body1}','2022-05-12 14:59:11','nginx',2), +(2,'2.2.2.2',8443,'192.168.77.88','/test2','get',2,400,'{head}','{erro}','2022-05-11 15:00:02','bind',2), +(3,'3.3.3.3',8443,'192.168.74.32','/test3','post',1,404,'{head}','{not found}','2022-04-10 15:00:52','nginx',2), +(4,'1.1.1.1',8443,'192.168.32.46','/test4','get',1,200,'{head2}','{body2}','2022-05-09 11:56:55','bind',2), +(5,'1.1.1.1',443,'192.168.32.47','/test1','post',1,200,'{head1}','{body1}','2022-05-08 16:58:48','nginx',2), +(6,'4.4.4.4',443,'192.168.1.1','/test4','get',1,200,'{head4}','{body4}','2022-05-07 14:37:43','bind',2), +(7,'5.5.5.5',443,'192.168.5.5','/test5','del',3,500,'{head5}','{body5}','2022-05-06 14:38:40','nginx',2), +(8,'6.6.6.6',443,'192.168.5.6','/test6','get',3,500,'{head6}','{body6}','2022-05-05 09:06:47','bind',2), +(9,'2.2.2.2',443,'192.168.77.88','/test2','get',2,400,'{head}','{erro}','2022-04-01 14:21:42','bind',1), +(10,'3.3.3.3',443,'192.168.74.31','/test3','post',1,404,'{head}','{not found}','2022-04-01 14:22:31','bind',1), +(11,'7.7.7.7',443,'192.168.77.77','/test7','post',1,404,'{head}','{not found}','2022-05-06 16:53:13','bind',2), +(12,'8.8.8.8',443,'192.168.88.88','/test8','post',1,404,'{head}','{not found}','2022-05-06 16:54:53','nginx',2), +(13,'9.9.9.9',443,'192.168.99.99','/test9','post',1,404,'{head}','{not found}','2022-05-06 16:54:59','nginx',2), +(14,'9.9.9.8',443,'192.168.99.98','/test98','post',1,404,'{head}','{not found}','2022-05-06 16:55:28','nginx',2), +(15,'9.9.9.7',443,'192.168.99.97','/test97','post',1,404,'{head}','{not found}','2022-05-13 16:59:18',NULL,2); + +/*Table structure for table `forward_dns` */ + +DROP TABLE IF EXISTS `forward_dns`; + +CREATE TABLE `forward_dns` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `forwarder` varchar(128) DEFAULT NULL, + `upstream` varchar(128) DEFAULT NULL, + `epoch` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; + +/*Data for the table `forward_dns` */ + +insert into `forward_dns`(`id`,`forwarder`,`upstream`,`epoch`) values +(1,'1.1.1.1','2.2.2.2',2), +(2,'2.2.2.2','1.1.1.1',2), +(3,'2.2.2.2','2.2.2.2',2), +(4,'3.3.3.3','4.4.4.4',2), +(5,'1.1.1.1','5.5.5.5',1), +(6,'2.2.2.2','6.6.6.6',1); + +/*Table structure for table `ip_cert` */ + +DROP TABLE IF EXISTS `ip_cert`; + +CREATE TABLE `ip_cert` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ip` varchar(128) DEFAULT NULL, + `port` int(11) DEFAULT NULL, + `certificate` varchar(5120) DEFAULT NULL, + `ca` varchar(128) DEFAULT NULL, + `timestamp` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_ip` (`ip`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; + +/*Data for the table `ip_cert` */ + +insert into `ip_cert`(`id`,`ip`,`port`,`certificate`,`ca`,`timestamp`) values +(1,'1.1.1.1',8443,'t1证书','t1证书颁发者','2022-04-27 15:01:33'), +(2,'2.2.2.2',8443,'t2证书','t2证书颁发者','2022-04-27 15:01:49'), +(3,'3.3.3.3',8443,'t3证书','t3证书颁发者','2022-04-27 15:02:01'), +(4,'1.1.1.1',8443,'t1证书2','t1证书颁发者2','2022-05-06 09:03:22'), +(5,'2.2.2.2',443,'t2证书443','t2证书颁发者443','2022-05-18 13:51:00'), +(6,'3.3.3.3',443,'t3证书443','t3证书颁发者443','2022-05-18 13:51:01'); + +/*Table structure for table `ip_information` */ + +DROP TABLE IF EXISTS `ip_information`; + +CREATE TABLE `ip_information` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ip` varchar(128) DEFAULT NULL, + `country` varchar(50) DEFAULT NULL, + `province` varchar(50) DEFAULT NULL, + `city` varchar(50) DEFAULT NULL, + `district` varchar(50) DEFAULT NULL, + `provider` varchar(50) DEFAULT NULL, + `isp` varchar(50) DEFAULT NULL, + `asnumber` int(11) DEFAULT NULL, + `timestamp` datetime DEFAULT NULL, + `zipcode` varchar(50) DEFAULT NULL, + `timezone` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_ip` (`ip`) +) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; + +/*Data for the table `ip_information` */ + +insert into `ip_information`(`id`,`ip`,`country`,`province`,`city`,`district`,`provider`,`isp`,`asnumber`,`timestamp`,`zipcode`,`timezone`) values +(1,'1.1.1.1','中国','河北','邢台','1','华为','华为',123456789,'2022-04-27 14:55:00','100000','UTC'), +(2,'2.2.2.2','哥伦比亚','德克萨斯州','纽约','2','特斯拉','特斯拉',987654321,'2022-04-27 14:56:27','500000','USA'), +(3,'3.3.3.3','刚果','伦敦省','伦敦市','3','长安','长安',741852963,'2022-04-27 14:57:31','800000','UK'), +(4,'4.4.4.4','日本','北京','怀柔','4','烤鸭','烤鸭',8888888,'2022-04-28 11:16:40','100010','UTC'), +(5,'5.5.5.5','韩国','河南','郑州','5','三星','三星',55555555,'2022-05-06 14:39:53','100010','UTC'), +(6,'6.6.6.6','英国','河北','石家庄','5','苹果','苹果',666666,'2022-05-13 14:25:55','100010','UTC'), +(7,'7.7.7.7','法国','江苏','南京','5','移动','移动',77777777,'2022-05-13 14:30:16','100010','UTC'), +(8,'8.8.8.8','德国','柏林','柏林',NULL,'运营商1','运营商1',8888888,'2022-05-17 16:58:06','100010',NULL), +(9,'9.9.9.9','瑞典','斯德哥尔摩','斯德哥尔摩',NULL,'运营商2','运营商2',999999,'2022-05-17 16:58:10','100010',NULL), +(10,'9.9.9.8','丹麦','哥本哈根','哥本哈根',NULL,'运营商3','运营商3',9999998,'2022-05-17 16:58:12','100010',NULL), +(11,'9.9.9.7','意大利','罗马','罗马',NULL,'运营商4','运营商4',333333,'2022-05-17 16:59:55',NULL,NULL); + +/*Table structure for table `mnt_app` */ + +DROP TABLE IF EXISTS `mnt_app`; + +CREATE TABLE `mnt_app` ( + `app_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(255) DEFAULT NULL COMMENT '应用名称', + `upload_path` varchar(255) DEFAULT NULL COMMENT '上传目录', + `deploy_path` varchar(255) DEFAULT NULL COMMENT '部署路径', + `backup_path` varchar(255) DEFAULT NULL COMMENT '备份路径', + `port` int(255) DEFAULT NULL COMMENT '应用端口', + `start_script` varchar(4000) DEFAULT NULL COMMENT '启动脚本', + `deploy_script` varchar(4000) DEFAULT NULL COMMENT '部署脚本', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`app_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='应用管理'; + +/*Data for the table `mnt_app` */ + +/*Table structure for table `mnt_database` */ + +DROP TABLE IF EXISTS `mnt_database`; + +CREATE TABLE `mnt_database` ( + `db_id` varchar(50) NOT NULL COMMENT 'ID', + `name` varchar(255) NOT NULL COMMENT '名称', + `jdbc_url` varchar(255) NOT NULL COMMENT 'jdbc连接', + `user_name` varchar(255) NOT NULL COMMENT '账号', + `pwd` varchar(255) NOT NULL COMMENT '密码', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`db_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='数据库管理'; + +/*Data for the table `mnt_database` */ + +/*Table structure for table `mnt_deploy` */ + +DROP TABLE IF EXISTS `mnt_deploy`; + +CREATE TABLE `mnt_deploy` ( + `deploy_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `app_id` bigint(20) DEFAULT NULL COMMENT '应用编号', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL, + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`deploy_id`) USING BTREE, + KEY `FK6sy157pseoxx4fmcqr1vnvvhy` (`app_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='部署管理'; + +/*Data for the table `mnt_deploy` */ + +/*Table structure for table `mnt_deploy_history` */ + +DROP TABLE IF EXISTS `mnt_deploy_history`; + +CREATE TABLE `mnt_deploy_history` ( + `history_id` varchar(50) NOT NULL COMMENT 'ID', + `app_name` varchar(255) NOT NULL COMMENT '应用名称', + `deploy_date` datetime NOT NULL COMMENT '部署日期', + `deploy_user` varchar(50) NOT NULL COMMENT '部署用户', + `ip` varchar(20) NOT NULL COMMENT '服务器IP', + `deploy_id` bigint(20) DEFAULT NULL COMMENT '部署编号', + PRIMARY KEY (`history_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='部署历史管理'; + +/*Data for the table `mnt_deploy_history` */ + +/*Table structure for table `mnt_deploy_server` */ + +DROP TABLE IF EXISTS `mnt_deploy_server`; + +CREATE TABLE `mnt_deploy_server` ( + `deploy_id` bigint(20) NOT NULL COMMENT '部署ID', + `server_id` bigint(20) NOT NULL COMMENT '服务ID', + PRIMARY KEY (`deploy_id`,`server_id`) USING BTREE, + KEY `FKeaaha7jew9a02b3bk9ghols53` (`server_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='应用与服务器关联'; + +/*Data for the table `mnt_deploy_server` */ + +/*Table structure for table `mnt_server` */ + +DROP TABLE IF EXISTS `mnt_server`; + +CREATE TABLE `mnt_server` ( + `server_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `account` varchar(50) DEFAULT NULL COMMENT '账号', + `ip` varchar(20) DEFAULT NULL COMMENT 'IP地址', + `name` varchar(100) DEFAULT NULL COMMENT '名称', + `password` varchar(100) DEFAULT NULL COMMENT '密码', + `port` int(11) DEFAULT NULL COMMENT '端口', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`server_id`) USING BTREE, + KEY `idx_ip` (`ip`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='服务器管理'; + +/*Data for the table `mnt_server` */ + +/*Table structure for table `nonstandard_dns` */ + +DROP TABLE IF EXISTS `nonstandard_dns`; + +CREATE TABLE `nonstandard_dns` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ip` varchar(128) DEFAULT NULL, + `record` varchar(128) DEFAULT NULL, + `epoch` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; + +/*Data for the table `nonstandard_dns` */ + +insert into `nonstandard_dns`(`id`,`ip`,`record`,`epoch`) values +(1,'1.1.1.1','aaaaa',2), +(2,'1.1.1.1','vvvvv',2), +(3,'2.2.2.2','22aaaa',2), +(4,'3.3.3.3','33aaaaa',2), +(5,'4.4.4.4','444aaaa',2), +(6,'5.5.5.5','555aaaa',2); + +/*Table structure for table `scan_result` */ + +DROP TABLE IF EXISTS `scan_result`; + +CREATE TABLE `scan_result` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ip` varchar(128) DEFAULT NULL, + `flags` int(11) DEFAULT NULL, + `opcode` tinyint(4) DEFAULT NULL, + `qr` tinyint(4) DEFAULT NULL, + `aa` tinyint(4) DEFAULT NULL, + `ra` tinyint(4) DEFAULT NULL, + `rcode` int(4) DEFAULT NULL, + `query_name` varchar(256) DEFAULT NULL, + `query_response` varchar(512) DEFAULT NULL, + `component` varchar(128) DEFAULT NULL, + `epoch` int(11) DEFAULT NULL, + `scan_type` tinyint(4) DEFAULT NULL, + `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8; + +/*Data for the table `scan_result` */ + +insert into `scan_result`(`id`,`ip`,`flags`,`opcode`,`qr`,`aa`,`ra`,`rcode`,`query_name`,`query_response`,`component`,`epoch`,`scan_type`,`time`) values +(1,'1.1.1.1',NULL,NULL,NULL,1,1,200,'1.1.1.1请求域名','1.1.1.1应答结果','bind',2,NULL,'2022-05-17 09:49:53'), +(2,'2.2.2.2',NULL,NULL,NULL,2,2,400,'2.2.2.2请求域名','2.2.2.2应答结果','bind',2,NULL,'2022-05-16 16:26:15'), +(3,'3.3.3.3',NULL,NULL,NULL,3,3,500,'3.3.3.3请求域名','3.3.3.3应答结果','bind',2,NULL,'2022-05-16 16:26:12'), +(4,'4.4.4.4',NULL,NULL,NULL,4,4,404,'4.4.4.4请求域名','4.4.4.4应答结果','unbound',2,NULL,'2022-05-16 16:26:12'), +(5,'5.5.5.5',NULL,NULL,NULL,5,5,500,'5.5.5.5请求域名','5.5.5.5应答结果','unbound',2,NULL,'2022-05-16 16:26:11'), +(6,'1.1.1.1',NULL,NULL,NULL,3,4,404,'1.1.1.1请求域名2','1.1.1.1应答结果2','bind',2,NULL,'2022-05-16 16:26:11'), +(7,'6.6.6.6',NULL,NULL,NULL,6,6,200,'6.6.6.6请求域名','6.6.6.6应答结果','bind',2,NULL,'2022-05-16 16:26:10'), +(8,'7.7.7.7',NULL,NULL,NULL,7,7,400,'7.7.7.7请求域名','7.7.7.7请求域名','bind',2,NULL,'2022-05-16 16:26:09'), +(9,'8.8.8.8',NULL,NULL,NULL,8,8,400,'8.8.8.8请求域名','8.8.8.8请求域名','bind',2,NULL,'2022-05-16 16:26:09'), +(10,'9.9.9.9',NULL,NULL,NULL,9,9,400,'9.9.9.9请求域名','9.9.9.9请求域名','bind',2,NULL,'2022-05-16 16:26:08'), +(11,'9.9.9.8',NULL,NULL,NULL,9,9,400,'9.9.9.9请求域名2','9.9.9.9请求域名2','bind',2,NULL,'2022-05-16 16:26:07'), +(12,'9.9.9.7',NULL,NULL,NULL,9,9,400,'9.9.9.9请求域名3','9.9.9.9请求域名3','bind',2,NULL,'2022-05-16 16:26:07'), +(13,'9.9.9.6',NULL,NULL,NULL,9,9,400,'9.9.9.9请求域名4','9.9.9.9请求域名4','bind',2,NULL,'2022-05-16 16:26:06'), +(14,'1.1.1.1',NULL,NULL,NULL,1,1,200,'1.1.1.1请求域名2','9.9.9.9请求域名4','bind',1,NULL,'2022-05-16 16:26:04'), +(15,'2.2.2.2',NULL,NULL,NULL,2,2,200,'2.2.2.2请求域名2','2.2.2.2请求域名2','bind',1,NULL,'2022-05-16 16:26:02'); + +/*Table structure for table `sys_dept` */ + +DROP TABLE IF EXISTS `sys_dept`; + +CREATE TABLE `sys_dept` ( + `dept_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `pid` bigint(20) DEFAULT NULL COMMENT '上级部门', + `sub_count` int(5) DEFAULT '0' COMMENT '子部门数目', + `name` varchar(255) NOT NULL COMMENT '名称', + `dept_sort` int(5) DEFAULT '999' COMMENT '排序', + `enabled` bit(1) NOT NULL COMMENT '状态', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`dept_id`) USING BTREE, + KEY `inx_pid` (`pid`), + KEY `inx_enabled` (`enabled`) +) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='部门'; + +/*Data for the table `sys_dept` */ + +insert into `sys_dept`(`dept_id`,`pid`,`sub_count`,`name`,`dept_sort`,`enabled`,`create_by`,`update_by`,`create_time`,`update_time`) values +(2,7,1,'研发部',3,'','admin','admin','2019-03-25 09:15:32','2020-08-02 14:48:47'), +(5,7,0,'运维部',4,'','admin','admin','2019-03-25 09:20:44','2020-05-17 14:27:27'), +(6,8,0,'测试部',6,'','admin','admin','2019-03-25 09:52:18','2020-06-08 11:59:21'), +(7,NULL,2,'华南分部',0,'','admin','admin','2019-03-25 11:04:50','2020-06-08 12:08:56'), +(8,NULL,2,'华北分部',1,'','admin','admin','2019-03-25 11:04:53','2020-05-14 12:54:00'), +(15,8,0,'UI部门',7,'','admin','admin','2020-05-13 22:56:53','2020-05-14 12:54:13'), +(17,2,0,'研发一组',999,'','admin','admin','2020-08-02 14:49:07','2020-08-02 14:49:07'); + +/*Table structure for table `sys_dict` */ + +DROP TABLE IF EXISTS `sys_dict`; + +CREATE TABLE `sys_dict` ( + `dict_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(255) NOT NULL COMMENT '字典名称', + `description` varchar(255) DEFAULT NULL COMMENT '描述', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`dict_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='数据字典'; + +/*Data for the table `sys_dict` */ + +insert into `sys_dict`(`dict_id`,`name`,`description`,`create_by`,`update_by`,`create_time`,`update_time`) values +(1,'user_status','用户状态',NULL,NULL,'2019-10-27 20:31:36',NULL), +(4,'dept_status','部门状态',NULL,NULL,'2019-10-27 20:31:36',NULL), +(5,'job_status','岗位状态',NULL,NULL,'2019-10-27 20:31:36',NULL); + +/*Table structure for table `sys_dict_detail` */ + +DROP TABLE IF EXISTS `sys_dict_detail`; + +CREATE TABLE `sys_dict_detail` ( + `detail_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `dict_id` bigint(11) DEFAULT NULL COMMENT '字典id', + `label` varchar(255) NOT NULL COMMENT '字典标签', + `value` varchar(255) NOT NULL COMMENT '字典值', + `dict_sort` int(5) DEFAULT NULL COMMENT '排序', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`detail_id`) USING BTREE, + KEY `FK5tpkputc6d9nboxojdbgnpmyb` (`dict_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='数据字典详情'; + +/*Data for the table `sys_dict_detail` */ + +insert into `sys_dict_detail`(`detail_id`,`dict_id`,`label`,`value`,`dict_sort`,`create_by`,`update_by`,`create_time`,`update_time`) values +(1,1,'激活','true',1,NULL,NULL,'2019-10-27 20:31:36',NULL), +(2,1,'禁用','false',2,NULL,NULL,NULL,NULL), +(3,4,'启用','true',1,NULL,NULL,NULL,NULL), +(4,4,'停用','false',2,NULL,NULL,'2019-10-27 20:31:36',NULL), +(5,5,'启用','true',1,NULL,NULL,NULL,NULL), +(6,5,'停用','false',2,NULL,NULL,'2019-10-27 20:31:36',NULL); + +/*Table structure for table `sys_job` */ + +DROP TABLE IF EXISTS `sys_job`; + +CREATE TABLE `sys_job` ( + `job_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(255) NOT NULL COMMENT '岗位名称', + `enabled` bit(1) NOT NULL COMMENT '岗位状态', + `job_sort` int(5) DEFAULT NULL COMMENT '排序', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`job_id`) USING BTREE, + UNIQUE KEY `uniq_name` (`name`), + KEY `inx_enabled` (`enabled`) +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='岗位'; + +/*Data for the table `sys_job` */ + +insert into `sys_job`(`job_id`,`name`,`enabled`,`job_sort`,`create_by`,`update_by`,`create_time`,`update_time`) values +(8,'人事专员','',3,NULL,NULL,'2019-03-29 14:52:28',NULL), +(10,'产品经理','',4,NULL,NULL,'2019-03-29 14:55:51',NULL), +(11,'全栈开发','',2,NULL,'admin','2019-03-31 13:39:30','2020-05-05 11:33:43'), +(12,'软件测试','',5,NULL,'admin','2019-03-31 13:39:43','2020-05-10 19:56:26'); + +/*Table structure for table `sys_log` */ + +DROP TABLE IF EXISTS `sys_log`; + +CREATE TABLE `sys_log` ( + `log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `description` varchar(255) DEFAULT NULL, + `log_type` varchar(255) DEFAULT NULL, + `method` varchar(255) DEFAULT NULL, + `params` text, + `request_ip` varchar(255) DEFAULT NULL, + `time` bigint(20) DEFAULT NULL, + `username` varchar(255) DEFAULT NULL, + `address` varchar(255) DEFAULT NULL, + `browser` varchar(255) DEFAULT NULL, + `exception_detail` text, + `create_time` datetime DEFAULT NULL, + PRIMARY KEY (`log_id`) USING BTREE, + KEY `log_create_time_index` (`create_time`), + KEY `inx_log_type` (`log_type`) +) ENGINE=InnoDB AUTO_INCREMENT=3549 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='系统日志'; + +/*Data for the table `sys_log` */ + +insert into `sys_log`(`log_id`,`description`,`log_type`,`method`,`params`,`request_ip`,`time`,`username`,`address`,`browser`,`exception_detail`,`create_time`) values +(3537,'修改用户','INFO','com.example.modules.system.rest.UserController.updateUser()','{\"gender\":\"男\",\"nickName\":\"测试\",\"roles\":[],\"jobs\":[{\"updateTime\":1589111786000,\"enabled\":true,\"jobSort\":5,\"updateBy\":\"admin\",\"createTime\":1554010783000,\"name\":\"软件测试\",\"id\":12}],\"avatarPath\":\"/Users/jie/Documents/work/me/admin/eladmin/~/avatar/avatar-20200806032259161.png\",\"updateTime\":1599273818000,\"dept\":{\"subCount\":0,\"name\":\"研发部\",\"id\":2},\"isAdmin\":false,\"enabled\":true,\"avatarName\":\"avatar-20200806032259161.png\",\"createBy\":\"admin\",\"phone\":\"19999999999\",\"pwdResetTime\":1588495111000,\"updateBy\":\"admin\",\"createTime\":1588648549000,\"id\":2,\"email\":\"[email protected]\",\"username\":\"test\"}','192.168.32.87',144,'admin','内网IP','Chrome 98.0.4758.102',NULL,'2022-04-24 11:18:20'), +(3538,'新增用户','INFO','com.example.modules.system.controller.UserController.createUser()','{\"gender\":\"男\",\"nickName\":\"aaa\",\"roles\":[{\"level\":3,\"dataScope\":\"本级\",\"id\":2}],\"jobs\":[{\"id\":8}],\"updateTime\":1650790301429,\"dept\":{\"subCount\":0,\"id\":8},\"isAdmin\":false,\"enabled\":true,\"password\":\"$2a$10$39eu19DlibPMfC9EEPPErO86uBAZhCzySlhvSn/Evg0gdInNeNB3W\",\"createBy\":\"admin\",\"phone\":\"15014236547\",\"updateBy\":\"admin\",\"createTime\":1650790301429,\"id\":3,\"email\":\"[email protected]\",\"username\":\"test2\"}','192.168.32.87',171,'admin','内网IP','Chrome 98.0.4758.102',NULL,'2022-04-24 16:51:41'), +(3539,'新增用户','ERROR','com.example.modules.system.controller.UserController.createUser()','{\"gender\":\"男\",\"nickName\":\"test3\",\"roles\":[{\"level\":3,\"dataScope\":\"本级\",\"id\":2}],\"jobs\":[{\"id\":8}],\"dept\":{\"subCount\":0,\"id\":7},\"isAdmin\":false,\"enabled\":true,\"password\":\"$2a$10$w8i0HM4aRHvCeVBg/KCx/O0kwDxrFDBpxvDX5ojBJ7xywJWEoDB6S\",\"phone\":\"15033669955\",\"email\":\"[email protected]\",\"username\":\"test3\"}','192.168.32.87',34422,'admin','内网IP','Chrome 98.0.4758.102','com.example.exception.EntityExistException: User with email [email protected] existed\r\n at com.example.modules.system.service.impl.UserServiceImpl.create(UserServiceImpl.java:90)\r\n at com.example.modules.system.service.impl.UserServiceImpl$$FastClassBySpringCGLIB$$5003e55c.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)\r\n at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)\r\n at com.example.modules.system.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$ea52fc62.create(<generated>)\r\n at com.example.modules.system.controller.UserController.createUser(UserController.java:109)\r\n at com.example.modules.system.controller.UserController$$FastClassBySpringCGLIB$$3a3729d2.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)\r\n at com.example.aspect.LogAspect.logAround(LogAspect.java:68)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)\r\n at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:69)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)\r\n at com.example.modules.system.controller.UserController$$EnhancerBySpringCGLIB$$9d3d2338.createUser(<generated>)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)\r\n at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)\r\n at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\r\n at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\r\n at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)\r\n at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:113)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at com.example.modules.security.security.TokenFilter.doFilter(TokenFilter.java:90)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)\r\n at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)\r\n at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)\r\n at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\r\n at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\r\n at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\r\n at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\r\n at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)\r\n at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)\r\n at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n at java.lang.Thread.run(Thread.java:748)\r\n','2022-04-24 16:59:29'), +(3540,'修改用户','INFO','com.example.modules.system.controller.UserController.updateUser()','{\"gender\":\"男\",\"nickName\":\"管理员\",\"roles\":[],\"jobs\":[{\"updateTime\":1588649623000,\"enabled\":true,\"jobSort\":2,\"updateBy\":\"admin\",\"createTime\":1554010770000,\"name\":\"全栈开发\",\"id\":11}],\"avatarPath\":\"/Users/jie/Documents/work/me/admin/eladmin/~/avatar/avatar-20200806032259161.png\",\"updateTime\":1599273811000,\"dept\":{\"subCount\":0,\"name\":\"研发部\",\"id\":2},\"isAdmin\":false,\"enabled\":true,\"avatarName\":\"avatar-20200806032259161.png\",\"phone\":\"18888888888\",\"pwdResetTime\":1588495111000,\"updateBy\":\"admin\",\"createTime\":1534986716000,\"id\":1,\"email\":\"[email protected]\",\"username\":\"admin\"}','192.168.32.87',52,'admin','内网IP','Chrome 98.0.4758.102',NULL,'2022-04-24 17:03:00'), +(3541,'新增用户','INFO','com.example.modules.system.controller.UserController.createUser()','{\"gender\":\"男\",\"nickName\":\"xx\",\"roles\":[{\"level\":3,\"dataScope\":\"本级\",\"id\":2}],\"jobs\":[{\"id\":8}],\"updateTime\":1650793621130,\"dept\":{\"subCount\":0,\"id\":7},\"isAdmin\":false,\"enabled\":true,\"password\":\"$2a$10$NGkgAoFjWGUueMJ81409I.mAJXa2KHf9b9GwgWZOCN8TdL35lLigy\",\"createBy\":\"admin\",\"phone\":\"15044878963\",\"updateBy\":\"admin\",\"createTime\":1650793621130,\"id\":4,\"email\":\"[email protected]\",\"username\":\"xx\"}','192.168.32.87',166,'admin','内网IP','Chrome 98.0.4758.102',NULL,'2022-04-24 17:47:01'), +(3542,'新增用户','ERROR','com.example.modules.system.controller.UserController.createUser()','{\"gender\":\"男\",\"nickName\":\"xxx\",\"isAdmin\":false,\"enabled\":true,\"phone\":\"15044878963\",\"email\":\"[email protected]\",\"username\":\"xxx\"}','192.168.32.87',5,'admin','内网IP','PostmanRuntime 7.28.4','java.lang.NullPointerException\r\n at com.example.modules.system.service.impl.RoleServiceImpl.findByRoles(RoleServiceImpl.java:158)\r\n at com.example.modules.system.service.impl.RoleServiceImpl$$FastClassBySpringCGLIB$$dc8a47d1.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:687)\r\n at com.example.modules.system.service.impl.RoleServiceImpl$$EnhancerBySpringCGLIB$$9cac769b.findByRoles(<generated>)\r\n at com.example.modules.system.controller.UserController.checkLevel(UserController.java:191)\r\n at com.example.modules.system.controller.UserController.createUser(UserController.java:106)\r\n at com.example.modules.system.controller.UserController$$FastClassBySpringCGLIB$$3a3729d2.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)\r\n at com.example.aspect.LogAspect.logAround(LogAspect.java:68)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)\r\n at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:69)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)\r\n at com.example.modules.system.controller.UserController$$EnhancerBySpringCGLIB$$c18ababd.createUser(<generated>)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)\r\n at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)\r\n at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\r\n at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\r\n at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)\r\n at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:113)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at com.example.modules.security.security.TokenFilter.doFilter(TokenFilter.java:90)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)\r\n at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)\r\n at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)\r\n at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\r\n at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\r\n at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\r\n at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\r\n at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)\r\n at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)\r\n at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n at java.lang.Thread.run(Thread.java:748)\r\n','2022-04-24 17:49:17'), +(3543,'新增用户','ERROR','com.example.modules.system.controller.UserController.createUser()','{\"gender\":\"男\",\"nickName\":\"xxx\",\"isAdmin\":false,\"enabled\":true,\"phone\":\"15044878963\",\"email\":\"[email protected]\",\"username\":\"xxx\"}','192.168.32.87',6,'admin','内网IP','PostmanRuntime 7.28.4','java.lang.NullPointerException\r\n at com.example.modules.system.service.impl.RoleServiceImpl.findByRoles(RoleServiceImpl.java:158)\r\n at com.example.modules.system.service.impl.RoleServiceImpl$$FastClassBySpringCGLIB$$dc8a47d1.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:687)\r\n at com.example.modules.system.service.impl.RoleServiceImpl$$EnhancerBySpringCGLIB$$9cac769b.findByRoles(<generated>)\r\n at com.example.modules.system.controller.UserController.checkLevel(UserController.java:191)\r\n at com.example.modules.system.controller.UserController.createUser(UserController.java:106)\r\n at com.example.modules.system.controller.UserController$$FastClassBySpringCGLIB$$3a3729d2.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)\r\n at com.example.aspect.LogAspect.logAround(LogAspect.java:68)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)\r\n at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:69)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)\r\n at com.example.modules.system.controller.UserController$$EnhancerBySpringCGLIB$$c18ababd.createUser(<generated>)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)\r\n at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)\r\n at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\r\n at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\r\n at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)\r\n at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:113)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at com.example.modules.security.security.TokenFilter.doFilter(TokenFilter.java:90)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)\r\n at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)\r\n at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)\r\n at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\r\n at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\r\n at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\r\n at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\r\n at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)\r\n at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)\r\n at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n at java.lang.Thread.run(Thread.java:748)\r\n','2022-04-24 17:49:31'), +(3544,'新增用户','ERROR','com.example.modules.system.controller.UserController.createUser()','{\"gender\":\"男\",\"nickName\":\"xxx\",\"isAdmin\":false,\"enabled\":true,\"password\":\"$2a$10$yT504iKWln9Oi9ETxlXYe.1emlR9hqIL.utpSTXWrx2iFW51oIyXq\",\"phone\":\"15044878963\",\"email\":\"[email protected]\",\"username\":\"xxx\"}','192.168.32.87',102,'admin','内网IP','PostmanRuntime 7.28.4','com.example.exception.EntityExistException: User with phone 15044878963 existed\r\n at com.example.modules.system.service.impl.UserServiceImpl.create(UserServiceImpl.java:93)\r\n at com.example.modules.system.service.impl.UserServiceImpl$$FastClassBySpringCGLIB$$5003e55c.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)\r\n at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)\r\n at com.example.modules.system.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$9777835f.create(<generated>)\r\n at com.example.modules.system.controller.UserController.createUser(UserController.java:109)\r\n at com.example.modules.system.controller.UserController$$FastClassBySpringCGLIB$$3a3729d2.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)\r\n at com.example.aspect.LogAspect.logAround(LogAspect.java:68)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)\r\n at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:69)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)\r\n at com.example.modules.system.controller.UserController$$EnhancerBySpringCGLIB$$1e21cf61.createUser(<generated>)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)\r\n at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)\r\n at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\r\n at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\r\n at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)\r\n at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:113)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at com.example.modules.security.security.TokenFilter.doFilter(TokenFilter.java:90)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)\r\n at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)\r\n at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)\r\n at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\r\n at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\r\n at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\r\n at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\r\n at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)\r\n at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)\r\n at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n at java.lang.Thread.run(Thread.java:748)\r\n','2022-04-24 17:52:01'), +(3545,'新增用户','INFO','com.example.modules.system.controller.UserController.createUser()','{\"gender\":\"男\",\"nickName\":\"xxx\",\"updateTime\":1650793939421,\"isAdmin\":false,\"enabled\":true,\"password\":\"$2a$10$y6hqVUiy6YSLngBuK4v/weonLYkyuIltwG0HTUCMTuCNtnGkFsDpW\",\"createBy\":\"admin\",\"phone\":\"15044878962\",\"updateBy\":\"admin\",\"createTime\":1650793939421,\"id\":5,\"email\":\"[email protected]\",\"username\":\"xxx\"}','192.168.32.87',121,'admin','内网IP','PostmanRuntime 7.28.4',NULL,'2022-04-24 17:52:19'), +(3546,'新增用户','INFO','com.example.modules.system.controller.UserController.createUser()','{\"gender\":\"男\",\"nickName\":\"ssss\",\"roles\":[{\"level\":3,\"dataScope\":\"本级\",\"id\":1}],\"jobs\":[{\"id\":8}],\"updateTime\":1650873057518,\"dept\":{\"subCount\":0,\"id\":7},\"isAdmin\":false,\"enabled\":true,\"password\":\"$2a$10$P.hvDg2NaJs/kYeLn15u4upYvYxbl4HB4ExNERrU1SM5EqTQF2Hae\",\"createBy\":\"admin\",\"phone\":\"15033698785\",\"updateBy\":\"admin\",\"createTime\":1650873057518,\"id\":6,\"email\":\"[email protected]\",\"username\":\"bbbb\"}','192.168.32.87',14796,'admin','内网IP','Chrome 98.0.4758.102',NULL,'2022-04-25 15:50:59'), +(3547,'修改用户','ERROR','com.example.modules.system.controller.UserController.updateUser()','{\"gender\":\"男\",\"nickName\":\"ssss\",\"roles\":[{\"level\":3,\"dataScope\":\"本级\",\"id\":2}],\"jobs\":[{\"id\":8}],\"updateTime\":1650873058000,\"dept\":{\"subCount\":0,\"name\":\"华南分部\",\"id\":7},\"isAdmin\":false,\"enabled\":true,\"createBy\":\"admin\",\"phone\":\"15033698785\",\"updateBy\":\"admin\",\"createTime\":1650873058000,\"id\":6,\"email\":\"[email protected]\",\"username\":\"bbbb\"}','192.168.32.87',3,'admin','内网IP','Chrome 98.0.4758.102','org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet\r\n at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:281)\r\n at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)\r\n at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528)\r\n at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)\r\n at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)\r\n at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:154)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:149)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)\r\n at com.sun.proxy.$Proxy171.findByUserId(Unknown Source)\r\n at com.example.modules.system.service.impl.RoleServiceImpl.findByUsersId(RoleServiceImpl.java:153)\r\n at com.example.modules.system.service.impl.RoleServiceImpl$$FastClassBySpringCGLIB$$dc8a47d1.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:687)\r\n at com.example.modules.system.service.impl.RoleServiceImpl$$EnhancerBySpringCGLIB$$d77f5b25.findByUsersId(<generated>)\r\n at com.example.modules.system.controller.UserController.checkLevel(UserController.java:190)\r\n at com.example.modules.system.controller.UserController.updateUser(UserController.java:118)\r\n at com.example.modules.system.controller.UserController$$FastClassBySpringCGLIB$$3a3729d2.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)\r\n at com.example.aspect.LogAspect.logAround(LogAspect.java:68)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)\r\n at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)\r\n at com.example.modules.system.controller.UserController$$EnhancerBySpringCGLIB$$111a6b16.updateUser(<generated>)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)\r\n at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)\r\n at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\r\n at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\r\n at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:920)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)\r\n at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:113)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at com.example.modules.security.security.TokenFilter.doFilter(TokenFilter.java:89)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)\r\n at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)\r\n at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)\r\n at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\r\n at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\r\n at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\r\n at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\r\n at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)\r\n at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)\r\n at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n at java.lang.Thread.run(Thread.java:748)\r\nCaused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet\r\n at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63)\r\n at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)\r\n at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)\r\n at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)\r\n at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:67)\r\n at org.hibernate.loader.Loader.getResultSet(Loader.java:2341)\r\n at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2094)\r\n at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2056)\r\n at org.hibernate.loader.Loader.doQuery(Loader.java:953)\r\n at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:350)\r\n at org.hibernate.loader.Loader.doList(Loader.java:2887)\r\n at org.hibernate.loader.Loader.doList(Loader.java:2869)\r\n at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2701)\r\n at org.hibernate.loader.Loader.list(Loader.java:2696)\r\n at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:338)\r\n at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2142)\r\n at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1163)\r\n at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:173)\r\n at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1533)\r\n at org.hibernate.query.Query.getResultList(Query.java:165)\r\n at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:126)\r\n at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:88)\r\n at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:154)\r\n at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:142)\r\n at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:618)\r\n at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:605)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)\r\n at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)\r\n ... 122 more\r\nCaused by: java.sql.SQLSyntaxErrorException: Table \'eladmin.sys_users_roles\' doesn\'t exist\r\n at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)\r\n at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)\r\n at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)\r\n at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)\r\n at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1003)\r\n at net.sf.log4jdbc.sql.jdbcapi.PreparedStatementSpy.executeQuery(PreparedStatementSpy.java:780)\r\n at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_executeQuery(FilterChainImpl.java:3240)\r\n at com.alibaba.druid.filter.FilterEventAdapter.preparedStatement_executeQuery(FilterEventAdapter.java:465)\r\n at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_executeQuery(FilterChainImpl.java:3237)\r\n at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.executeQuery(PreparedStatementProxyImpl.java:181)\r\n at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227)\r\n at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57)\r\n ... 150 more\r\n','2022-04-25 15:56:34'), +(3548,'新增用户','ERROR','com.example.modules.system.controller.UserController.createUser()','{\"gender\":\"男\",\"nickName\":\"xxxcds\",\"roles\":[{\"level\":3,\"dataScope\":\"本级\",\"id\":1}],\"jobs\":[{\"id\":8}],\"updateTime\":1650873529243,\"dept\":{\"subCount\":0,\"id\":7},\"isAdmin\":false,\"enabled\":true,\"password\":\"$2a$10$960h5w5vd1RMOIdiBp24HO2squJKm0D0EsZN5yMbZ7SF6VJlkaihW\",\"createBy\":\"admin\",\"phone\":\"15032145698\",\"updateBy\":\"admin\",\"createTime\":1650873529243,\"id\":7,\"email\":\"[email protected]\",\"username\":\"ghjg\"}','192.168.32.87',97,'admin','内网IP','Chrome 98.0.4758.102','org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute statement\r\n at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:281)\r\n at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)\r\n at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:538)\r\n at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743)\r\n at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711)\r\n at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:633)\r\n at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:386)\r\n at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)\r\n at com.example.modules.system.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$adc982a6.create(<generated>)\r\n at com.example.modules.system.controller.UserController.createUser(UserController.java:109)\r\n at com.example.modules.system.controller.UserController$$FastClassBySpringCGLIB$$3a3729d2.invoke(<generated>)\r\n at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)\r\n at com.example.aspect.LogAspect.logAround(LogAspect.java:68)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)\r\n at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)\r\n at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)\r\n at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\r\n at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)\r\n at com.example.modules.system.controller.UserController$$EnhancerBySpringCGLIB$$111a6b16.createUser(<generated>)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n at java.lang.reflect.Method.invoke(Method.java:498)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)\r\n at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)\r\n at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)\r\n at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)\r\n at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\r\n at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\r\n at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)\r\n at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:113)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)\r\n at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at com.example.modules.security.security.TokenFilter.doFilter(TokenFilter.java:89)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)\r\n at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)\r\n at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)\r\n at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)\r\n at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)\r\n at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\r\n at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\r\n at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\r\n at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\r\n at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)\r\n at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)\r\n at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n at java.lang.Thread.run(Thread.java:748)\r\nCaused by: org.hibernate.exception.SQLGrammarException: could not execute statement\r\n at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63)\r\n at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)\r\n at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)\r\n at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)\r\n at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)\r\n at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46)\r\n at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1357)\r\n at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:52)\r\n at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)\r\n at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)\r\n at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)\r\n at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)\r\n at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)\r\n at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)\r\n at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)\r\n at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1363)\r\n at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:454)\r\n at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3213)\r\n at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2381)\r\n at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447)\r\n at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)\r\n at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40)\r\n at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)\r\n at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)\r\n at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:534)\r\n ... 118 more\r\nCaused by: java.sql.SQLSyntaxErrorException: Table \'eladmin.sys_users_roles\' doesn\'t exist\r\n at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)\r\n at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)\r\n at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)\r\n at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)\r\n at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)\r\n at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)\r\n at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347)\r\n at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025)\r\n at net.sf.log4jdbc.sql.jdbcapi.PreparedStatementSpy.executeUpdate(PreparedStatementSpy.java:1080)\r\n at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_executeUpdate(FilterChainImpl.java:3253)\r\n at com.alibaba.druid.filter.FilterAdapter.preparedStatement_executeUpdate(FilterAdapter.java:1092)\r\n at com.alibaba.druid.filter.FilterEventAdapter.preparedStatement_executeUpdate(FilterEventAdapter.java:491)\r\n at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_executeUpdate(FilterChainImpl.java:3251)\r\n at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.executeUpdate(PreparedStatementProxyImpl.java:194)\r\n at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeUpdate(DruidPooledPreparedStatement.java:255)\r\n at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)\r\n ... 138 more\r\n','2022-04-25 15:58:49'); + +/*Table structure for table `sys_menu` */ + +DROP TABLE IF EXISTS `sys_menu`; + +CREATE TABLE `sys_menu` ( + `menu_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `pid` bigint(20) DEFAULT NULL COMMENT '上级菜单ID', + `sub_count` int(5) DEFAULT '0' COMMENT '子菜单数目', + `type` int(11) DEFAULT NULL COMMENT '菜单类型', + `title` varchar(255) DEFAULT NULL COMMENT '菜单标题', + `name` varchar(255) DEFAULT NULL COMMENT '组件名称', + `component` varchar(255) DEFAULT NULL COMMENT '组件', + `menu_sort` int(5) DEFAULT NULL COMMENT '排序', + `icon` varchar(255) DEFAULT NULL COMMENT '图标', + `path` varchar(255) DEFAULT NULL COMMENT '链接地址', + `i_frame` bit(1) DEFAULT NULL COMMENT '是否外链', + `cache` bit(1) DEFAULT b'0' COMMENT '缓存', + `hidden` bit(1) DEFAULT b'0' COMMENT '隐藏', + `permission` varchar(255) DEFAULT NULL COMMENT '权限', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`menu_id`) USING BTREE, + UNIQUE KEY `uniq_title` (`title`), + UNIQUE KEY `uniq_name` (`name`), + KEY `inx_pid` (`pid`) +) ENGINE=InnoDB AUTO_INCREMENT=117 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='系统菜单'; + +/*Data for the table `sys_menu` */ + +INSERT INTO `sys_menu` VALUES (1, NULL, 7, 0, '系统管理', NULL, NULL, 1, 'system', 'system', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-18 15:11:29', NULL); +INSERT INTO `sys_menu` VALUES (2, 1, 3, 1, '用户管理', 'User', 'system/user/index', 2, 'peoples', 'user', b'0', b'0', b'0', 'user:list', NULL, NULL, '2018-12-18 15:14:44', NULL); +INSERT INTO `sys_menu` VALUES (3, 1, 3, 1, '角色管理', 'Role', 'system/role/index', 3, 'role', 'role', b'0', b'0', b'0', 'roles:list', NULL, NULL, '2018-12-18 15:16:07', NULL); +INSERT INTO `sys_menu` VALUES (5, 1, 3, 1, '菜单管理', 'Menu', 'system/menu/index', 5, 'menu', 'menu', b'0', b'0', b'0', 'menu:list', NULL, NULL, '2018-12-18 15:17:28', NULL); +INSERT INTO `sys_menu` VALUES (6, NULL, 5, 0, '系统监控', NULL, NULL, 10, 'monitor', 'monitor', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-18 15:17:48', NULL); +INSERT INTO `sys_menu` VALUES (7, 6, 0, 1, '操作日志', 'Log', 'monitor/log/index', 11, 'log', 'logs', b'0', b'1', b'0', NULL, NULL, 'admin', '2018-12-18 15:18:26', '2020-06-06 13:11:57'); +INSERT INTO `sys_menu` VALUES (9, 6, 0, 1, 'SQL监控', 'Sql', 'monitor/sql/index', 18, 'sqlMonitor', 'druid', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-18 15:19:34', NULL); +INSERT INTO `sys_menu` VALUES (10, NULL, 5, 0, 'DNS研究', NULL, NULL, 50, 'zujian', 'components', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-19 13:38:16', NULL); +INSERT INTO `sys_menu` VALUES (11, 10, 0, 1, '清华大学-NISL', 'Icons', 'components/icons/index', 51, 'icon', 'http://netsec.ccert.edu.cn/chs/', b'1', b'0', b'0', NULL, NULL, NULL, '2018-12-19 13:38:49', NULL); +INSERT INTO `sys_menu` VALUES (14, 36, 0, 1, 'DNS审查', 'Email', 'tools/email/index', 32, 'email', 'email', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-27 10:13:09', NULL); +INSERT INTO `sys_menu` VALUES (15, 10, 0, 1, 'APNIC', 'Editor', 'components/Editor', 52, 'fwb', 'https://blog.apnic.net/', b'1', b'0', b'0', NULL, NULL, NULL, '2018-12-27 11:58:25', NULL); +INSERT INTO `sys_menu` VALUES (18, 36, 0, 1, 'DNS威胁', 'Storage', 'tools/storage/index', 34, 'qiniu', 'storage', b'0', b'0', b'0', 'storage:list', NULL, NULL, '2018-12-31 11:12:15', NULL); +INSERT INTO `sys_menu` VALUES (19, 36, 0, 1, 'DNS集中性', 'AliPay', 'tools/aliPay/index', 35, 'alipay', 'aliPay', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-31 14:52:38', NULL); +INSERT INTO `sys_menu` VALUES (21, NULL, 1, 0, '关于', NULL, '', 900, 'menu', 'nested', b'0', b'0', b'0', NULL, NULL, 'admin', '2019-01-04 16:22:03', '2020-06-21 17:27:35'); +INSERT INTO `sys_menu` VALUES (22, 21, 0, 1, '二级菜单1', '', 'nested/menu2/index', 999, 'menu', 'menu2-1', b'0', b'0', b'1', NULL, NULL, 'admin', '2019-01-04 16:23:29', '2020-06-21 17:27:20'); +INSERT INTO `sys_menu` VALUES (23, 21, 0, 1, 'MESA', NULL, 'nested/menu2/index', 999, 'menu', 'https://www.mesalab.cn/', b'1', b'0', b'0', NULL, NULL, NULL, '2019-01-04 16:23:57', NULL); +INSERT INTO `sys_menu` VALUES (24, 22, 0, 1, '三级菜单1', 'Test', 'nested/menu1/menu1-1', 999, 'menu', 'menu1-1', b'0', b'0', b'1', NULL, NULL, NULL, '2019-01-04 16:24:48', NULL); +INSERT INTO `sys_menu` VALUES (27, 22, 0, 1, '三级菜单2', NULL, 'nested/menu1/menu1-2', 999, 'menu', 'menu1-2', b'0', b'0', b'1', NULL, NULL, NULL, '2019-01-07 17:27:32', NULL); +INSERT INTO `sys_menu` VALUES (28, 1, 3, 1, '任务调度', 'Timing', 'system/timing/index', 999, 'timing', 'timing', b'0', b'0', b'0', 'timing:list', NULL, NULL, '2019-01-07 20:34:40', NULL); +INSERT INTO `sys_menu` VALUES (30, 36, 0, 1, '新型DNS协议', 'GeneratorIndex', 'generator/index', 37, 'dev', 'generator', b'0', b'1', b'0', NULL, NULL, NULL, '2019-01-11 15:45:55', NULL); +INSERT INTO `sys_menu` VALUES (32, 6, 0, 1, '异常日志', 'ErrorLog', 'monitor/log/errorLog', 12, 'error', 'errorLog', b'0', b'0', b'0', NULL, NULL, NULL, '2019-01-13 13:49:03', NULL); +INSERT INTO `sys_menu` VALUES (33, 10, 0, 1, '南加州大学-ANT Lab', 'Markdown', 'components/MarkDown', 53, 'markdown', 'https://ant.isi.edu/', b'1', b'0', b'0', NULL, NULL, NULL, '2019-03-08 13:46:44', NULL); +INSERT INTO `sys_menu` VALUES (34, 10, 0, 1, '普林斯顿大学-Noise Lab', 'YamlEdit', 'components/YamlEdit', 54, 'dev', 'https://noise.cs.uchicago.edu/security.html', b'1', b'0', b'0', NULL, NULL, NULL, '2019-03-08 15:49:40', NULL); +INSERT INTO `sys_menu` VALUES (35, 1, 3, 1, '部门管理', 'Dept', 'system/dept/index', 6, 'dept', 'dept', b'0', b'0', b'0', 'dept:list', NULL, NULL, '2019-03-25 09:46:00', NULL); +INSERT INTO `sys_menu` VALUES (36, NULL, 7, 0, '专题报告', NULL, '', 30, 'sys-tools', 'sys-tools', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-29 10:57:35', NULL); +INSERT INTO `sys_menu` VALUES (37, 1, 3, 1, '岗位管理', 'Job', 'system/job/index', 7, 'Steve-Jobs', 'job', b'0', b'0', b'0', 'job:list', NULL, NULL, '2019-03-29 13:51:18', NULL); +INSERT INTO `sys_menu` VALUES (38, 36, 0, 1, '接口文档', 'Swagger', 'tools/swagger/index', 36, 'swagger', 'swagger2', b'0', b'0', b'1', NULL, NULL, NULL, '2019-03-29 19:57:53', NULL); +INSERT INTO `sys_menu` VALUES (39, 1, 3, 1, '字典管理', 'Dict', 'system/dict/index', 8, 'dictionary', 'dict', b'0', b'0', b'0', 'dict:list', NULL, NULL, '2019-04-10 11:49:04', NULL); +INSERT INTO `sys_menu` VALUES (41, 6, 0, 1, '在线用户', 'OnlineUser', 'monitor/online/index', 10, 'Steve-Jobs', 'online', b'0', b'0', b'0', NULL, NULL, NULL, '2019-10-26 22:08:43', NULL); +INSERT INTO `sys_menu` VALUES (44, 2, 0, 2, '用户新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'user:add', NULL, NULL, '2019-10-29 10:59:46', NULL); +INSERT INTO `sys_menu` VALUES (45, 2, 0, 2, '用户编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'user:edit', NULL, NULL, '2019-10-29 11:00:08', NULL); +INSERT INTO `sys_menu` VALUES (46, 2, 0, 2, '用户删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'user:del', NULL, NULL, '2019-10-29 11:00:23', NULL); +INSERT INTO `sys_menu` VALUES (48, 3, 0, 2, '角色创建', NULL, '', 2, '', '', b'0', b'0', b'0', 'roles:add', NULL, NULL, '2019-10-29 12:45:34', NULL); +INSERT INTO `sys_menu` VALUES (49, 3, 0, 2, '角色修改', NULL, '', 3, '', '', b'0', b'0', b'0', 'roles:edit', NULL, NULL, '2019-10-29 12:46:16', NULL); +INSERT INTO `sys_menu` VALUES (50, 3, 0, 2, '角色删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'roles:del', NULL, NULL, '2019-10-29 12:46:51', NULL); +INSERT INTO `sys_menu` VALUES (52, 5, 0, 2, '菜单新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'menu:add', NULL, NULL, '2019-10-29 12:55:07', NULL); +INSERT INTO `sys_menu` VALUES (53, 5, 0, 2, '菜单编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'menu:edit', NULL, NULL, '2019-10-29 12:55:40', NULL); +INSERT INTO `sys_menu` VALUES (54, 5, 0, 2, '菜单删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'menu:del', NULL, NULL, '2019-10-29 12:56:00', NULL); +INSERT INTO `sys_menu` VALUES (56, 35, 0, 2, '部门新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'dept:add', NULL, NULL, '2019-10-29 12:57:09', NULL); +INSERT INTO `sys_menu` VALUES (57, 35, 0, 2, '部门编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'dept:edit', NULL, NULL, '2019-10-29 12:57:27', NULL); +INSERT INTO `sys_menu` VALUES (58, 35, 0, 2, '部门删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'dept:del', NULL, NULL, '2019-10-29 12:57:41', NULL); +INSERT INTO `sys_menu` VALUES (60, 37, 0, 2, '岗位新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'job:add', NULL, NULL, '2019-10-29 12:58:27', NULL); +INSERT INTO `sys_menu` VALUES (61, 37, 0, 2, '岗位编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'job:edit', NULL, NULL, '2019-10-29 12:58:45', NULL); +INSERT INTO `sys_menu` VALUES (62, 37, 0, 2, '岗位删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'job:del', NULL, NULL, '2019-10-29 12:59:04', NULL); +INSERT INTO `sys_menu` VALUES (64, 39, 0, 2, '字典新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'dict:add', NULL, NULL, '2019-10-29 13:00:17', NULL); +INSERT INTO `sys_menu` VALUES (65, 39, 0, 2, '字典编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'dict:edit', NULL, NULL, '2019-10-29 13:00:42', NULL); +INSERT INTO `sys_menu` VALUES (66, 39, 0, 2, '字典删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'dict:del', NULL, NULL, '2019-10-29 13:00:59', NULL); +INSERT INTO `sys_menu` VALUES (73, 28, 0, 2, '任务新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'timing:add', NULL, NULL, '2019-10-29 13:07:28', NULL); +INSERT INTO `sys_menu` VALUES (74, 28, 0, 2, '任务编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'timing:edit', NULL, NULL, '2019-10-29 13:07:41', NULL); +INSERT INTO `sys_menu` VALUES (75, 28, 0, 2, '任务删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'timing:del', NULL, NULL, '2019-10-29 13:07:54', NULL); +INSERT INTO `sys_menu` VALUES (77, 18, 0, 2, '上传文件', NULL, '', 2, '', '', b'0', b'0', b'0', 'storage:add', NULL, NULL, '2019-10-29 13:09:09', NULL); +INSERT INTO `sys_menu` VALUES (78, 18, 0, 2, '文件编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'storage:edit', NULL, NULL, '2019-10-29 13:09:22', NULL); +INSERT INTO `sys_menu` VALUES (79, 18, 0, 2, '文件删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'storage:del', NULL, NULL, '2019-10-29 13:09:34', NULL); +INSERT INTO `sys_menu` VALUES (80, 6, 0, 1, '服务监控', 'ServerMonitor', 'monitor/server/index', 14, 'codeConsole', 'server', b'0', b'0', b'0', 'monitor:list', NULL, 'admin', '2019-11-07 13:06:39', '2020-05-04 18:20:50'); +INSERT INTO `sys_menu` VALUES (82, 36, 0, 1, '生成配置', 'GeneratorConfig', 'generator/config', 33, 'dev', 'generator/config/:tableName', b'0', b'1', b'1', '', NULL, NULL, '2019-11-17 20:08:56', NULL); +INSERT INTO `sys_menu` VALUES (83, 10, 0, 1, '图表库', 'Echarts', 'components/Echarts', 50, 'chart', 'echarts', b'0', b'1', b'1', '', NULL, NULL, '2019-11-21 09:04:32', NULL); +INSERT INTO `sys_menu` VALUES (102, 97, 0, 2, '删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'deployHistory:del', NULL, NULL, '2019-11-17 09:32:48', NULL); +INSERT INTO `sys_menu` VALUES (103, 92, 0, 2, '服务器新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'serverDeploy:add', NULL, NULL, '2019-11-17 11:08:33', NULL); +INSERT INTO `sys_menu` VALUES (104, 92, 0, 2, '服务器编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'serverDeploy:edit', NULL, NULL, '2019-11-17 11:08:57', NULL); +INSERT INTO `sys_menu` VALUES (105, 92, 0, 2, '服务器删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'serverDeploy:del', NULL, NULL, '2019-11-17 11:09:15', NULL); +INSERT INTO `sys_menu` VALUES (106, 93, 0, 2, '应用新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'app:add', NULL, NULL, '2019-11-17 11:10:03', NULL); +INSERT INTO `sys_menu` VALUES (107, 93, 0, 2, '应用编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'app:edit', NULL, NULL, '2019-11-17 11:10:28', NULL); +INSERT INTO `sys_menu` VALUES (108, 93, 0, 2, '应用删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'app:del', NULL, NULL, '2019-11-17 11:10:55', NULL); +INSERT INTO `sys_menu` VALUES (109, 94, 0, 2, '部署新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'deploy:add', NULL, NULL, '2019-11-17 11:11:22', NULL); +INSERT INTO `sys_menu` VALUES (110, 94, 0, 2, '部署编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'deploy:edit', NULL, NULL, '2019-11-17 11:11:41', NULL); +INSERT INTO `sys_menu` VALUES (111, 94, 0, 2, '部署删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'deploy:del', NULL, NULL, '2019-11-17 11:12:01', NULL); +INSERT INTO `sys_menu` VALUES (112, 98, 0, 2, '数据库新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'database:add', NULL, NULL, '2019-11-17 11:12:43', NULL); +INSERT INTO `sys_menu` VALUES (113, 98, 0, 2, '数据库编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'database:edit', NULL, NULL, '2019-11-17 11:12:58', NULL); +INSERT INTO `sys_menu` VALUES (114, 98, 0, 2, '数据库删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'database:del', NULL, NULL, '2019-11-17 11:13:14', NULL); +INSERT INTO `sys_menu` VALUES (116, 36, 0, 1, '生成预览', 'Preview', 'generator/preview', 999, 'java', 'generator/preview/:tableName', b'0', b'1', b'1', NULL, NULL, NULL, '2019-11-26 14:54:36', NULL); + +/*Table structure for table `sys_quartz_job` */ + +DROP TABLE IF EXISTS `sys_quartz_job`; + +CREATE TABLE `sys_quartz_job` ( + `job_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `bean_name` varchar(255) DEFAULT NULL COMMENT 'Spring Bean名称', + `cron_expression` varchar(255) DEFAULT NULL COMMENT 'cron 表达式', + `is_pause` bit(1) DEFAULT NULL COMMENT '状态:1暂停、0启用', + `job_name` varchar(255) DEFAULT NULL COMMENT '任务名称', + `method_name` varchar(255) DEFAULT NULL COMMENT '方法名称', + `params` varchar(255) DEFAULT NULL COMMENT '参数', + `description` varchar(255) DEFAULT NULL COMMENT '备注', + `person_in_charge` varchar(100) DEFAULT NULL COMMENT '负责人', + `email` varchar(100) DEFAULT NULL COMMENT '报警邮箱', + `sub_task` varchar(100) DEFAULT NULL COMMENT '子任务ID', + `pause_after_failure` bit(1) DEFAULT NULL COMMENT '任务失败后是否暂停', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`job_id`) USING BTREE, + KEY `inx_is_pause` (`is_pause`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='定时任务'; + +/*Data for the table `sys_quartz_job` */ + +insert into `sys_quartz_job`(`job_id`,`bean_name`,`cron_expression`,`is_pause`,`job_name`,`method_name`,`params`,`description`,`person_in_charge`,`email`,`sub_task`,`pause_after_failure`,`create_by`,`update_by`,`create_time`,`update_time`) values +(2,'testTask','0/5 * * * * ?','','测试1','run1','test','带参测试,多参使用json','测试',NULL,NULL,NULL,NULL,'admin','2019-08-22 14:08:29','2020-05-24 13:58:33'), +(3,'testTask','0/5 * * * * ?','','测试','run','','不带参测试','Zheng Jie','','5,6','',NULL,'admin','2019-09-26 16:44:39','2020-05-24 14:48:12'), +(5,'Test','0/5 * * * * ?','','任务告警测试','run',NULL,'测试','test','',NULL,'','admin','admin','2020-05-05 20:32:41','2020-05-05 20:36:13'), +(6,'testTask','0/5 * * * * ?','','测试3','run2',NULL,'测试3','Zheng Jie','',NULL,'','admin','admin','2020-05-05 20:35:41','2020-05-05 20:36:07'); + +/*Table structure for table `sys_quartz_log` */ + +DROP TABLE IF EXISTS `sys_quartz_log`; + +CREATE TABLE `sys_quartz_log` ( + `log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `bean_name` varchar(255) DEFAULT NULL, + `create_time` datetime DEFAULT NULL, + `cron_expression` varchar(255) DEFAULT NULL, + `exception_detail` text, + `is_success` bit(1) DEFAULT NULL, + `job_name` varchar(255) DEFAULT NULL, + `method_name` varchar(255) DEFAULT NULL, + `params` varchar(255) DEFAULT NULL, + `time` bigint(20) DEFAULT NULL, + PRIMARY KEY (`log_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='定时任务日志'; + +/*Data for the table `sys_quartz_log` */ + +/*Table structure for table `sys_role` */ + +DROP TABLE IF EXISTS `sys_role`; + +CREATE TABLE `sys_role` ( + `role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(255) NOT NULL COMMENT '名称', + `level` int(255) DEFAULT NULL COMMENT '角色级别', + `description` varchar(255) DEFAULT NULL COMMENT '描述', + `data_scope` varchar(255) DEFAULT NULL COMMENT '数据权限', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`role_id`) USING BTREE, + UNIQUE KEY `uniq_name` (`name`), + KEY `role_name_index` (`name`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='角色表'; + +/*Data for the table `sys_role` */ + +INSERT INTO `sys_role` VALUES (1, '超级管理员', 1, '-', '全部', NULL, 'admin', '2018-11-23 11:04:37', '2022-06-13 11:18:51'); +INSERT INTO `sys_role` VALUES (2, '普通用户', 2, '-', '本级', NULL, 'admin', '2018-11-23 13:09:06', '2020-09-05 10:45:12'); +INSERT INTO `sys_role` VALUES (3, '系统管理员', 1, '系统菜单,监控,用户,部门等系统信息管理员', '全部', 'admin', 'sysadmin', '2022-06-13 11:17:59', '2022-06-13 11:36:44'); + +/*Table structure for table `sys_roles_depts` */ + +DROP TABLE IF EXISTS `sys_roles_depts`; + +CREATE TABLE `sys_roles_depts` ( + `role_id` bigint(20) NOT NULL, + `dept_id` bigint(20) NOT NULL, + PRIMARY KEY (`role_id`,`dept_id`) USING BTREE, + KEY `FK7qg6itn5ajdoa9h9o78v9ksur` (`dept_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='角色部门关联'; + +/*Data for the table `sys_roles_depts` */ + +/*Table structure for table `sys_roles_menus` */ + +DROP TABLE IF EXISTS `sys_roles_menus`; + +CREATE TABLE `sys_roles_menus` ( + `menu_id` bigint(20) NOT NULL COMMENT '菜单ID', + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + PRIMARY KEY (`menu_id`,`role_id`) USING BTREE, + KEY `FKcngg2qadojhi3a651a5adkvbq` (`role_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='角色菜单关联'; + +/*Data for the table `sys_roles_menus` */ + +INSERT INTO `sys_roles_menus` VALUES (1, 2); +INSERT INTO `sys_roles_menus` VALUES (1, 3); +INSERT INTO `sys_roles_menus` VALUES (2, 2); +INSERT INTO `sys_roles_menus` VALUES (2, 3); +INSERT INTO `sys_roles_menus` VALUES (3, 3); +INSERT INTO `sys_roles_menus` VALUES (5, 3); +INSERT INTO `sys_roles_menus` VALUES (6, 1); +INSERT INTO `sys_roles_menus` VALUES (6, 2); +INSERT INTO `sys_roles_menus` VALUES (6, 3); +INSERT INTO `sys_roles_menus` VALUES (7, 1); +INSERT INTO `sys_roles_menus` VALUES (7, 2); +INSERT INTO `sys_roles_menus` VALUES (7, 3); +INSERT INTO `sys_roles_menus` VALUES (9, 1); +INSERT INTO `sys_roles_menus` VALUES (9, 2); +INSERT INTO `sys_roles_menus` VALUES (9, 3); +INSERT INTO `sys_roles_menus` VALUES (10, 1); +INSERT INTO `sys_roles_menus` VALUES (10, 2); +INSERT INTO `sys_roles_menus` VALUES (11, 1); +INSERT INTO `sys_roles_menus` VALUES (11, 2); +INSERT INTO `sys_roles_menus` VALUES (14, 1); +INSERT INTO `sys_roles_menus` VALUES (14, 2); +INSERT INTO `sys_roles_menus` VALUES (15, 1); +INSERT INTO `sys_roles_menus` VALUES (15, 2); +INSERT INTO `sys_roles_menus` VALUES (18, 1); +INSERT INTO `sys_roles_menus` VALUES (19, 1); +INSERT INTO `sys_roles_menus` VALUES (19, 2); +INSERT INTO `sys_roles_menus` VALUES (21, 1); +INSERT INTO `sys_roles_menus` VALUES (21, 2); +INSERT INTO `sys_roles_menus` VALUES (22, 1); +INSERT INTO `sys_roles_menus` VALUES (22, 2); +INSERT INTO `sys_roles_menus` VALUES (23, 1); +INSERT INTO `sys_roles_menus` VALUES (23, 2); +INSERT INTO `sys_roles_menus` VALUES (24, 1); +INSERT INTO `sys_roles_menus` VALUES (24, 2); +INSERT INTO `sys_roles_menus` VALUES (27, 1); +INSERT INTO `sys_roles_menus` VALUES (27, 2); +INSERT INTO `sys_roles_menus` VALUES (28, 3); +INSERT INTO `sys_roles_menus` VALUES (30, 1); +INSERT INTO `sys_roles_menus` VALUES (30, 2); +INSERT INTO `sys_roles_menus` VALUES (32, 1); +INSERT INTO `sys_roles_menus` VALUES (32, 2); +INSERT INTO `sys_roles_menus` VALUES (32, 3); +INSERT INTO `sys_roles_menus` VALUES (33, 1); +INSERT INTO `sys_roles_menus` VALUES (33, 2); +INSERT INTO `sys_roles_menus` VALUES (34, 1); +INSERT INTO `sys_roles_menus` VALUES (34, 2); +INSERT INTO `sys_roles_menus` VALUES (35, 3); +INSERT INTO `sys_roles_menus` VALUES (36, 1); +INSERT INTO `sys_roles_menus` VALUES (36, 2); +INSERT INTO `sys_roles_menus` VALUES (37, 3); +INSERT INTO `sys_roles_menus` VALUES (38, 1); +INSERT INTO `sys_roles_menus` VALUES (39, 3); +INSERT INTO `sys_roles_menus` VALUES (41, 1); +INSERT INTO `sys_roles_menus` VALUES (41, 3); +INSERT INTO `sys_roles_menus` VALUES (44, 3); +INSERT INTO `sys_roles_menus` VALUES (45, 3); +INSERT INTO `sys_roles_menus` VALUES (46, 3); +INSERT INTO `sys_roles_menus` VALUES (48, 3); +INSERT INTO `sys_roles_menus` VALUES (49, 3); +INSERT INTO `sys_roles_menus` VALUES (50, 3); +INSERT INTO `sys_roles_menus` VALUES (52, 3); +INSERT INTO `sys_roles_menus` VALUES (53, 3); +INSERT INTO `sys_roles_menus` VALUES (54, 3); +INSERT INTO `sys_roles_menus` VALUES (56, 3); +INSERT INTO `sys_roles_menus` VALUES (57, 3); +INSERT INTO `sys_roles_menus` VALUES (58, 3); +INSERT INTO `sys_roles_menus` VALUES (60, 3); +INSERT INTO `sys_roles_menus` VALUES (61, 3); +INSERT INTO `sys_roles_menus` VALUES (62, 3); +INSERT INTO `sys_roles_menus` VALUES (64, 3); +INSERT INTO `sys_roles_menus` VALUES (65, 3); +INSERT INTO `sys_roles_menus` VALUES (66, 3); +INSERT INTO `sys_roles_menus` VALUES (73, 3); +INSERT INTO `sys_roles_menus` VALUES (74, 3); +INSERT INTO `sys_roles_menus` VALUES (75, 3); +INSERT INTO `sys_roles_menus` VALUES (77, 1); +INSERT INTO `sys_roles_menus` VALUES (78, 1); +INSERT INTO `sys_roles_menus` VALUES (79, 1); +INSERT INTO `sys_roles_menus` VALUES (80, 1); +INSERT INTO `sys_roles_menus` VALUES (80, 2); +INSERT INTO `sys_roles_menus` VALUES (80, 3); +INSERT INTO `sys_roles_menus` VALUES (82, 1); +INSERT INTO `sys_roles_menus` VALUES (82, 2); +INSERT INTO `sys_roles_menus` VALUES (83, 1); +INSERT INTO `sys_roles_menus` VALUES (83, 2); +INSERT INTO `sys_roles_menus` VALUES (90, 1); +INSERT INTO `sys_roles_menus` VALUES (92, 1); +INSERT INTO `sys_roles_menus` VALUES (93, 1); +INSERT INTO `sys_roles_menus` VALUES (94, 1); +INSERT INTO `sys_roles_menus` VALUES (97, 1); +INSERT INTO `sys_roles_menus` VALUES (98, 1); +INSERT INTO `sys_roles_menus` VALUES (102, 1); +INSERT INTO `sys_roles_menus` VALUES (103, 1); +INSERT INTO `sys_roles_menus` VALUES (104, 1); +INSERT INTO `sys_roles_menus` VALUES (105, 1); +INSERT INTO `sys_roles_menus` VALUES (106, 1); +INSERT INTO `sys_roles_menus` VALUES (107, 1); +INSERT INTO `sys_roles_menus` VALUES (108, 1); +INSERT INTO `sys_roles_menus` VALUES (109, 1); +INSERT INTO `sys_roles_menus` VALUES (110, 1); +INSERT INTO `sys_roles_menus` VALUES (111, 1); +INSERT INTO `sys_roles_menus` VALUES (112, 1); +INSERT INTO `sys_roles_menus` VALUES (113, 1); +INSERT INTO `sys_roles_menus` VALUES (114, 1); +INSERT INTO `sys_roles_menus` VALUES (116, 1); +INSERT INTO `sys_roles_menus` VALUES (116, 2); +INSERT INTO `sys_roles_menus` VALUES (120, 1); + +/*Table structure for table `sys_user` */ + +DROP TABLE IF EXISTS `sys_user`; + +CREATE TABLE `sys_user` ( + `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `dept_id` bigint(20) DEFAULT NULL COMMENT '部门名称', + `username` varchar(255) DEFAULT NULL COMMENT '用户名', + `nick_name` varchar(255) DEFAULT NULL COMMENT '昵称', + `gender` varchar(2) DEFAULT NULL COMMENT '性别', + `phone` varchar(255) DEFAULT NULL COMMENT '手机号码', + `email` varchar(255) DEFAULT NULL COMMENT '邮箱', + `avatar_name` varchar(255) DEFAULT NULL COMMENT '头像地址', + `avatar_path` varchar(255) DEFAULT NULL COMMENT '头像真实路径', + `password` varchar(255) DEFAULT NULL COMMENT '密码', + `is_admin` bit(1) DEFAULT b'0' COMMENT '是否为admin账号', + `enabled` bigint(20) DEFAULT NULL COMMENT '状态:1启用、0禁用', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `pwd_reset_time` datetime DEFAULT NULL COMMENT '修改密码的时间', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`user_id`) USING BTREE, + UNIQUE KEY `UK_kpubos9gc2cvtkb0thktkbkes` (`email`) USING BTREE, + UNIQUE KEY `username` (`username`) USING BTREE, + UNIQUE KEY `uniq_username` (`username`), + UNIQUE KEY `uniq_email` (`email`), + KEY `FK5rwmryny6jthaaxkogownknqp` (`dept_id`) USING BTREE, + KEY `FKpq2dhypk2qgt68nauh2by22jb` (`avatar_name`) USING BTREE, + KEY `inx_enabled` (`enabled`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='系统用户'; + +/*Data for the table `sys_user` */ + +INSERT INTO `sys_user` VALUES (1, 2, 'admin', '管理员', '男', '18888888888', '[email protected]', 'avatar-20200806032259161.png', '/Users/jie/Documents/work/me/admin/eladmin/~/avatar/avatar-20200806032259161.png', '$2a$10$Egp1/gvFlt7zhlXVfEFw4OfWQCGPw0ClmMcc6FjTnvXNRVf9zdMRa', b'1', 1, NULL, 'admin', '2020-05-03 16:38:31', '2018-08-23 09:11:56', '2022-04-24 17:03:00'); +INSERT INTO `sys_user` VALUES (2, 2, 'test', '测试', '男', '19999999999', '[email protected]', NULL, NULL, '$2a$10$4XcyudOYTSz6fue6KFNMHeUQnCX5jbBQypLEnGk1PmekXt5c95JcK', b'0', 1, 'admin', 'admin', NULL, '2020-05-05 11:15:49', '2022-04-24 11:18:18'); +INSERT INTO `sys_user` VALUES (3, 8, 'test2', 'aaa', '男', '15014236547', '[email protected]', NULL, NULL, '$2a$10$39eu19DlibPMfC9EEPPErO86uBAZhCzySlhvSn/Evg0gdInNeNB3W', b'0', 1, 'admin', 'admin', NULL, '2022-04-24 16:51:41', '2022-04-24 16:51:41'); +INSERT INTO `sys_user` VALUES (4, 7, 'xx', 'xx', '男', '15044878963', '[email protected]', NULL, NULL, '$2a$10$NGkgAoFjWGUueMJ81409I.mAJXa2KHf9b9GwgWZOCN8TdL35lLigy', b'0', 1, 'admin', 'admin', NULL, '2022-04-24 17:47:01', '2022-04-24 17:47:01'); +INSERT INTO `sys_user` VALUES (5, NULL, 'xxx', 'xxx', '男', '15044878962', '[email protected]', NULL, NULL, '$2a$10$y6hqVUiy6YSLngBuK4v/weonLYkyuIltwG0HTUCMTuCNtnGkFsDpW', b'0', 1, 'admin', 'admin', NULL, '2022-04-24 17:52:19', '2022-04-24 17:52:19'); +INSERT INTO `sys_user` VALUES (6, 7, 'bbbb', 'ssss', '男', '15033698785', '[email protected]', NULL, NULL, '$2a$10$P.hvDg2NaJs/kYeLn15u4upYvYxbl4HB4ExNERrU1SM5EqTQF2Hae', b'0', 1, 'admin', 'admin', NULL, '2022-04-25 15:50:58', '2022-04-25 15:50:58'); +INSERT INTO `sys_user` VALUES (7, 5, 'sysadmin', 'sysadmin', '男', '18765432100', '[email protected]', NULL, NULL, '$2a$10$Wp0dKiYZpAgNap.0NhK40.LEd2AgDTFC.i/unDcRPmICf9JMEcYzC', b'0', 1, 'admin', 'admin', NULL, '2022-06-13 11:20:03', '2022-06-13 11:20:03'); + +/*Table structure for table `sys_users_jobs` */ + +DROP TABLE IF EXISTS `sys_users_jobs`; + +CREATE TABLE `sys_users_jobs` ( + `user_id` bigint(20) NOT NULL COMMENT '用户ID', + `job_id` bigint(20) NOT NULL COMMENT '岗位ID', + PRIMARY KEY (`user_id`,`job_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +/*Data for the table `sys_users_jobs` */ + +insert into `sys_users_jobs`(`user_id`,`job_id`) values +(1,11), +(2,12), +(3,8), +(4,8), +(6,8); + +/*Table structure for table `sys_users_roles` */ + +DROP TABLE IF EXISTS `sys_users_roles`; + +CREATE TABLE `sys_users_roles` ( + `user_id` bigint(20) NOT NULL COMMENT '用户ID', + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + PRIMARY KEY (`user_id`,`role_id`) USING BTREE, + KEY `FKq4eq273l04bpu4efj0jd0jb98` (`role_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='用户角色关联'; + +/*Data for the table `sys_users_roles` */ + +insert into `sys_users_roles`(`user_id`,`role_id`) values +(1,1), +(6,1), +(2,2), +(3,2), +(4,2); + +/*Table structure for table `tool_alipay_config` */ + +DROP TABLE IF EXISTS `tool_alipay_config`; + +CREATE TABLE `tool_alipay_config` ( + `config_id` bigint(20) NOT NULL COMMENT 'ID', + `app_id` varchar(255) DEFAULT NULL COMMENT '应用ID', + `charset` varchar(255) DEFAULT NULL COMMENT '编码', + `format` varchar(255) DEFAULT NULL COMMENT '类型 固定格式json', + `gateway_url` varchar(255) DEFAULT NULL COMMENT '网关地址', + `notify_url` varchar(255) DEFAULT NULL COMMENT '异步回调', + `private_key` text COMMENT '私钥', + `public_key` text COMMENT '公钥', + `return_url` varchar(255) DEFAULT NULL COMMENT '回调地址', + `sign_type` varchar(255) DEFAULT NULL COMMENT '签名方式', + `sys_service_provider_id` varchar(255) DEFAULT NULL COMMENT '商户号', + PRIMARY KEY (`config_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='支付宝配置类'; + +/*Data for the table `tool_alipay_config` */ + +insert into `tool_alipay_config`(`config_id`,`app_id`,`charset`,`format`,`gateway_url`,`notify_url`,`private_key`,`public_key`,`return_url`,`sign_type`,`sys_service_provider_id`) values +(1,'2016091700532697','utf-8','JSON','https://openapi.alipaydev.com/gateway.do','http://api.auauz.net/api/aliPay/notify','MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC5js8sInU10AJ0cAQ8UMMyXrQ+oHZEkVt5lBwsStmTJ7YikVYgbskx1YYEXTojRsWCb+SH/kDmDU4pK/u91SJ4KFCRMF2411piYuXU/jF96zKrADznYh/zAraqT6hvAIVtQAlMHN53nx16rLzZ/8jDEkaSwT7+HvHiS+7sxSojnu/3oV7BtgISoUNstmSe8WpWHOaWv19xyS+Mce9MY4BfseFhzTICUymUQdd/8hXA28/H6osUfAgsnxAKv7Wil3aJSgaJczWuflYOve0dJ3InZkhw5Cvr0atwpk8YKBQjy5CdkoHqvkOcIB+cYHXJKzOE5tqU7inSwVbHzOLQ3XbnAgMBAAECggEAVJp5eT0Ixg1eYSqFs9568WdetUNCSUchNxDBu6wxAbhUgfRUGZuJnnAll63OCTGGck+EGkFh48JjRcBpGoeoHLL88QXlZZbC/iLrea6gcDIhuvfzzOffe1RcZtDFEj9hlotg8dQj1tS0gy9pN9g4+EBH7zeu+fyv+qb2e/v1l6FkISXUjpkD7RLQr3ykjiiEw9BpeKb7j5s7Kdx1NNIzhkcQKNqlk8JrTGDNInbDM6inZfwwIO2R1DHinwdfKWkvOTODTYa2MoAvVMFT9Bec9FbLpoWp7ogv1JMV9svgrcF9XLzANZ/OQvkbe9TV9GWYvIbxN6qwQioKCWO4GPnCAQKBgQDgW5MgfhX8yjXqoaUy/d1VjI8dHeIyw8d+OBAYwaxRSlCfyQ+tieWcR2HdTzPca0T0GkWcKZm0ei5xRURgxt4DUDLXNh26HG0qObbtLJdu/AuBUuCqgOiLqJ2f1uIbrz6OZUHns+bT/jGW2Ws8+C13zTCZkZt9CaQsrp3QOGDx5wKBgQDTul39hp3ZPwGNFeZdkGoUoViOSd5Lhowd5wYMGAEXWRLlU8z+smT5v0POz9JnIbCRchIY2FAPKRdVTICzmPk2EPJFxYTcwaNbVqL6lN7J2IlXXMiit5QbiLauo55w7plwV6LQmKm9KV7JsZs5XwqF7CEovI7GevFzyD3w+uizAQKBgC3LY1eRhOlpWOIAhpjG6qOoohmeXOphvdmMlfSHq6WYFqbWwmV4rS5d/6LNpNdL6fItXqIGd8I34jzql49taCmi+A2nlR/E559j0mvM20gjGDIYeZUz5MOE8k+K6/IcrhcgofgqZ2ZED1ksHdB/E8DNWCswZl16V1FrfvjeWSNnAoGAMrBplCrIW5xz+J0Hm9rZKrs+AkK5D4fUv8vxbK/KgxZ2KaUYbNm0xv39c+PZUYuFRCz1HDGdaSPDTE6WeWjkMQd5mS6ikl9hhpqFRkyh0d0fdGToO9yLftQKOGE/q3XUEktI1XvXF0xyPwNgUCnq0QkpHyGVZPtGFxwXiDvpvgECgYA5PoB+nY8iDiRaJNko9w0hL4AeKogwf+4TbCw+KWVEn6jhuJa4LFTdSqp89PktQaoVpwv92el/AhYjWOl/jVCm122f9b7GyoelbjMNolToDwe5pF5RnSpEuDdLy9MfE8LnE3PlbE7E5BipQ3UjSebkgNboLHH/lNZA5qvEtvbfvQ==','MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAut9evKRuHJ/2QNfDlLwvN/S8l9hRAgPbb0u61bm4AtzaTGsLeMtScetxTWJnVvAVpMS9luhEJjt+Sbk5TNLArsgzzwARgaTKOLMT1TvWAK5EbHyI+eSrc3s7Awe1VYGwcubRFWDm16eQLv0k7iqiw+4mweHSz/wWyvBJVgwLoQ02btVtAQErCfSJCOmt0Q/oJQjj08YNRV4EKzB19+f5A+HQVAKy72dSybTzAK+3FPtTtNen/+b5wGeat7c32dhYHnGorPkPeXLtsqqUTp1su5fMfd4lElNdZaoCI7osZxWWUo17vBCZnyeXc9fk0qwD9mK6yRAxNbrY72Xx5VqIqwIDAQAB','http://api.auauz.net/api/aliPay/return','RSA2','2088102176044281'); + +/*Table structure for table `tool_email_config` */ + +DROP TABLE IF EXISTS `tool_email_config`; + +CREATE TABLE `tool_email_config` ( + `config_id` bigint(20) NOT NULL COMMENT 'ID', + `from_user` varchar(255) DEFAULT NULL COMMENT '收件人', + `host` varchar(255) DEFAULT NULL COMMENT '邮件服务器SMTP地址', + `pass` varchar(255) DEFAULT NULL COMMENT '密码', + `port` varchar(255) DEFAULT NULL COMMENT '端口', + `user` varchar(255) DEFAULT NULL COMMENT '发件者用户名', + PRIMARY KEY (`config_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='邮箱配置'; + +/*Data for the table `tool_email_config` */ + +/*Table structure for table `tool_local_storage` */ + +DROP TABLE IF EXISTS `tool_local_storage`; + +CREATE TABLE `tool_local_storage` ( + `storage_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `real_name` varchar(255) DEFAULT NULL COMMENT '文件真实的名称', + `name` varchar(255) DEFAULT NULL COMMENT '文件名', + `suffix` varchar(255) DEFAULT NULL COMMENT '后缀', + `path` varchar(255) DEFAULT NULL COMMENT '路径', + `type` varchar(255) DEFAULT NULL COMMENT '类型', + `size` varchar(100) DEFAULT NULL COMMENT '大小', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`storage_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='本地存储'; + +/*Data for the table `tool_local_storage` */ + +/*Table structure for table `tool_qiniu_config` */ + +DROP TABLE IF EXISTS `tool_qiniu_config`; + +CREATE TABLE `tool_qiniu_config` ( + `config_id` bigint(20) NOT NULL COMMENT 'ID', + `access_key` text COMMENT 'accessKey', + `bucket` varchar(255) DEFAULT NULL COMMENT 'Bucket 识别符', + `host` varchar(255) NOT NULL COMMENT '外链域名', + `secret_key` text COMMENT 'secretKey', + `type` varchar(255) DEFAULT NULL COMMENT '空间类型', + `zone` varchar(255) DEFAULT NULL COMMENT '机房', + PRIMARY KEY (`config_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='七牛云配置'; + +/*Data for the table `tool_qiniu_config` */ + +/*Table structure for table `tool_qiniu_content` */ + +DROP TABLE IF EXISTS `tool_qiniu_content`; + +CREATE TABLE `tool_qiniu_content` ( + `content_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `bucket` varchar(255) DEFAULT NULL COMMENT 'Bucket 识别符', + `name` varchar(255) DEFAULT NULL COMMENT '文件名称', + `size` varchar(255) DEFAULT NULL COMMENT '文件大小', + `type` varchar(255) DEFAULT NULL COMMENT '文件类型:私有或公开', + `url` varchar(255) DEFAULT NULL COMMENT '文件url', + `suffix` varchar(255) DEFAULT NULL COMMENT '文件后缀', + `update_time` datetime DEFAULT NULL COMMENT '上传或同步的时间', + PRIMARY KEY (`content_id`) USING BTREE, + UNIQUE KEY `uniq_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='七牛云文件存储'; + +/*Data for the table `tool_qiniu_content` */ + +/*Table structure for table `vulnerability` */ + +DROP TABLE IF EXISTS `vulnerability`; + +CREATE TABLE `vulnerability` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `component` varchar(128) DEFAULT NULL, + `vulnerability` varchar(128) DEFAULT NULL, + `timestamp` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; + +/*Data for the table `vulnerability` */ + +insert into `vulnerability`(`id`,`component`,`vulnerability`,`timestamp`) values +(1,'nginx','nginx漏洞','2022-05-05 14:09:00'), +(2,'bind','bind漏洞','2022-05-05 14:09:13'), +(3,'unbound','unbound漏洞','2022-05-11 14:49:14'); + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/UI source code/dns-dev-2.0/sql/eladmin.sql b/UI source code/dns-dev-2.0/sql/eladmin.sql new file mode 100644 index 0000000..da53710 --- /dev/null +++ b/UI source code/dns-dev-2.0/sql/eladmin.sql @@ -0,0 +1,825 @@ +/* + Navicat Premium Data Transfer + + Source Server : localhost + Source Server Type : MySQL + Source Server Version : 100505 + Source Host : localhost:3306 + Source Schema : dns + + Target Server Type : MySQL + Target Server Version : 100505 + File Encoding : 65001 + + Date: 05/09/2020 10:49:19 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for code_column_config +-- ---------------------------- +DROP TABLE IF EXISTS `code_column_config`; +CREATE TABLE `code_column_config` ( + `column_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `table_name` varchar(255) DEFAULT NULL, + `column_name` varchar(255) DEFAULT NULL, + `column_type` varchar(255) DEFAULT NULL, + `dict_name` varchar(255) DEFAULT NULL, + `extra` varchar(255) DEFAULT NULL, + `form_show` bit(1) DEFAULT NULL, + `form_type` varchar(255) DEFAULT NULL, + `key_type` varchar(255) DEFAULT NULL, + `list_show` bit(1) DEFAULT NULL, + `not_null` bit(1) DEFAULT NULL, + `query_type` varchar(255) DEFAULT NULL, + `remark` varchar(255) DEFAULT NULL, + `date_annotation` varchar(255) DEFAULT NULL, + PRIMARY KEY (`column_id`) USING BTREE, + KEY `idx_table_name` (`table_name`) +) ENGINE=InnoDB AUTO_INCREMENT=191 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='代码生成字段信息存储'; + +-- ---------------------------- +-- Table structure for code_gen_config +-- ---------------------------- +DROP TABLE IF EXISTS `code_gen_config`; +CREATE TABLE `code_gen_config` ( + `config_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `table_name` varchar(255) DEFAULT NULL COMMENT '表名', + `author` varchar(255) DEFAULT NULL COMMENT '作者', + `cover` bit(1) DEFAULT NULL COMMENT '是否覆盖', + `module_name` varchar(255) DEFAULT NULL COMMENT '模块名称', + `pack` varchar(255) DEFAULT NULL COMMENT '至于哪个包下', + `path` varchar(255) DEFAULT NULL COMMENT '前端代码生成的路径', + `api_path` varchar(255) DEFAULT NULL COMMENT '前端Api文件路径', + `prefix` varchar(255) DEFAULT NULL COMMENT '表前缀', + `api_alias` varchar(255) DEFAULT NULL COMMENT '接口名称', + PRIMARY KEY (`config_id`) USING BTREE, + KEY `idx_table_name` (`table_name`(100)) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='代码生成器配置'; + +-- ---------------------------- +-- Table structure for mnt_app +-- ---------------------------- +DROP TABLE IF EXISTS `mnt_app`; +CREATE TABLE `mnt_app` ( + `app_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(255) DEFAULT NULL COMMENT '应用名称', + `upload_path` varchar(255) DEFAULT NULL COMMENT '上传目录', + `deploy_path` varchar(255) DEFAULT NULL COMMENT '部署路径', + `backup_path` varchar(255) DEFAULT NULL COMMENT '备份路径', + `port` int(255) DEFAULT NULL COMMENT '应用端口', + `start_script` varchar(4000) DEFAULT NULL COMMENT '启动脚本', + `deploy_script` varchar(4000) DEFAULT NULL COMMENT '部署脚本', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`app_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='应用管理'; + +-- ---------------------------- +-- Records of mnt_app +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for mnt_database +-- ---------------------------- +DROP TABLE IF EXISTS `mnt_database`; +CREATE TABLE `mnt_database` ( + `db_id` varchar(50) NOT NULL COMMENT 'ID', + `name` varchar(255) NOT NULL COMMENT '名称', + `jdbc_url` varchar(255) NOT NULL COMMENT 'jdbc连接', + `user_name` varchar(255) NOT NULL COMMENT '账号', + `pwd` varchar(255) NOT NULL COMMENT '密码', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`db_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='数据库管理'; + +-- ---------------------------- +-- Records of mnt_database +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for mnt_deploy +-- ---------------------------- +DROP TABLE IF EXISTS `mnt_deploy`; +CREATE TABLE `mnt_deploy` ( + `deploy_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `app_id` bigint(20) DEFAULT NULL COMMENT '应用编号', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL, + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`deploy_id`) USING BTREE, + KEY `FK6sy157pseoxx4fmcqr1vnvvhy` (`app_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='部署管理'; + +-- ---------------------------- +-- Records of mnt_deploy +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for mnt_deploy_history +-- ---------------------------- +DROP TABLE IF EXISTS `mnt_deploy_history`; +CREATE TABLE `mnt_deploy_history` ( + `history_id` varchar(50) NOT NULL COMMENT 'ID', + `app_name` varchar(255) NOT NULL COMMENT '应用名称', + `deploy_date` datetime NOT NULL COMMENT '部署日期', + `deploy_user` varchar(50) NOT NULL COMMENT '部署用户', + `ip` varchar(20) NOT NULL COMMENT '服务器IP', + `deploy_id` bigint(20) DEFAULT NULL COMMENT '部署编号', + PRIMARY KEY (`history_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='部署历史管理'; + +-- ---------------------------- +-- Records of mnt_deploy_history +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for mnt_deploy_server +-- ---------------------------- +DROP TABLE IF EXISTS `mnt_deploy_server`; +CREATE TABLE `mnt_deploy_server` ( + `deploy_id` bigint(20) NOT NULL COMMENT '部署ID', + `server_id` bigint(20) NOT NULL COMMENT '服务ID', + PRIMARY KEY (`deploy_id`,`server_id`) USING BTREE, + KEY `FKeaaha7jew9a02b3bk9ghols53` (`server_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='应用与服务器关联'; + +-- ---------------------------- +-- Records of mnt_deploy_server +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for mnt_server +-- ---------------------------- +DROP TABLE IF EXISTS `mnt_server`; +CREATE TABLE `mnt_server` ( + `server_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `account` varchar(50) DEFAULT NULL COMMENT '账号', + `ip` varchar(20) DEFAULT NULL COMMENT 'IP地址', + `name` varchar(100) DEFAULT NULL COMMENT '名称', + `password` varchar(100) DEFAULT NULL COMMENT '密码', + `port` int(11) DEFAULT NULL COMMENT '端口', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`server_id`) USING BTREE, + KEY `idx_ip` (`ip`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='服务器管理'; + +-- ---------------------------- +-- Table structure for sys_dept +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dept`; +CREATE TABLE `sys_dept` ( + `dept_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `pid` bigint(20) DEFAULT NULL COMMENT '上级部门', + `sub_count` int(5) DEFAULT 0 COMMENT '子部门数目', + `name` varchar(255) NOT NULL COMMENT '名称', + `dept_sort` int(5) DEFAULT 999 COMMENT '排序', + `enabled` bit(1) NOT NULL COMMENT '状态', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`dept_id`) USING BTREE, + KEY `inx_pid` (`pid`), + KEY `inx_enabled` (`enabled`) +) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='部门'; + +-- ---------------------------- +-- Records of sys_dept +-- ---------------------------- +BEGIN; +INSERT INTO `sys_dept` VALUES (2, 7, 1, '研发部', 3, b'1', 'admin', 'admin', '2019-03-25 09:15:32', '2020-08-02 14:48:47'); +INSERT INTO `sys_dept` VALUES (5, 7, 0, '运维部', 4, b'1', 'admin', 'admin', '2019-03-25 09:20:44', '2020-05-17 14:27:27'); +INSERT INTO `sys_dept` VALUES (6, 8, 0, '测试部', 6, b'1', 'admin', 'admin', '2019-03-25 09:52:18', '2020-06-08 11:59:21'); +INSERT INTO `sys_dept` VALUES (7, NULL, 2, '华南分部', 0, b'1', 'admin', 'admin', '2019-03-25 11:04:50', '2020-06-08 12:08:56'); +INSERT INTO `sys_dept` VALUES (8, NULL, 2, '华北分部', 1, b'1', 'admin', 'admin', '2019-03-25 11:04:53', '2020-05-14 12:54:00'); +INSERT INTO `sys_dept` VALUES (15, 8, 0, 'UI部门', 7, b'1', 'admin', 'admin', '2020-05-13 22:56:53', '2020-05-14 12:54:13'); +INSERT INTO `sys_dept` VALUES (17, 2, 0, '研发一组', 999, b'1', 'admin', 'admin', '2020-08-02 14:49:07', '2020-08-02 14:49:07'); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_dict +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict`; +CREATE TABLE `sys_dict` ( + `dict_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(255) NOT NULL COMMENT '字典名称', + `description` varchar(255) DEFAULT NULL COMMENT '描述', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`dict_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='数据字典'; + +-- ---------------------------- +-- Records of sys_dict +-- ---------------------------- +BEGIN; +INSERT INTO `sys_dict` VALUES (1, 'user_status', '用户状态', NULL, NULL, '2019-10-27 20:31:36', NULL); +INSERT INTO `sys_dict` VALUES (4, 'dept_status', '部门状态', NULL, NULL, '2019-10-27 20:31:36', NULL); +INSERT INTO `sys_dict` VALUES (5, 'job_status', '岗位状态', NULL, NULL, '2019-10-27 20:31:36', NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_dict_detail +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict_detail`; +CREATE TABLE `sys_dict_detail` ( + `detail_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `dict_id` bigint(11) DEFAULT NULL COMMENT '字典id', + `label` varchar(255) NOT NULL COMMENT '字典标签', + `value` varchar(255) NOT NULL COMMENT '字典值', + `dict_sort` int(5) DEFAULT NULL COMMENT '排序', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`detail_id`) USING BTREE, + KEY `FK5tpkputc6d9nboxojdbgnpmyb` (`dict_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='数据字典详情'; + +-- ---------------------------- +-- Records of sys_dict_detail +-- ---------------------------- +BEGIN; +INSERT INTO `sys_dict_detail` VALUES (1, 1, '激活', 'true', 1, NULL, NULL, '2019-10-27 20:31:36', NULL); +INSERT INTO `sys_dict_detail` VALUES (2, 1, '禁用', 'false', 2, NULL, NULL, NULL, NULL); +INSERT INTO `sys_dict_detail` VALUES (3, 4, '启用', 'true', 1, NULL, NULL, NULL, NULL); +INSERT INTO `sys_dict_detail` VALUES (4, 4, '停用', 'false', 2, NULL, NULL, '2019-10-27 20:31:36', NULL); +INSERT INTO `sys_dict_detail` VALUES (5, 5, '启用', 'true', 1, NULL, NULL, NULL, NULL); +INSERT INTO `sys_dict_detail` VALUES (6, 5, '停用', 'false', 2, NULL, NULL, '2019-10-27 20:31:36', NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_job +-- ---------------------------- +DROP TABLE IF EXISTS `sys_job`; +CREATE TABLE `sys_job` ( + `job_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(255) NOT NULL COMMENT '岗位名称', + `enabled` bit(1) NOT NULL COMMENT '岗位状态', + `job_sort` int(5) DEFAULT NULL COMMENT '排序', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`job_id`) USING BTREE, + UNIQUE KEY `uniq_name` (`name`), + KEY `inx_enabled` (`enabled`) +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='岗位'; + +-- ---------------------------- +-- Records of sys_job +-- ---------------------------- +BEGIN; +INSERT INTO `sys_job` VALUES (8, '人事专员', b'1', 3, NULL, NULL, '2019-03-29 14:52:28', NULL); +INSERT INTO `sys_job` VALUES (10, '产品经理', b'1', 4, NULL, NULL, '2019-03-29 14:55:51', NULL); +INSERT INTO `sys_job` VALUES (11, '全栈开发', b'1', 2, NULL, 'admin', '2019-03-31 13:39:30', '2020-05-05 11:33:43'); +INSERT INTO `sys_job` VALUES (12, '软件测试', b'1', 5, NULL, 'admin', '2019-03-31 13:39:43', '2020-05-10 19:56:26'); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_log`; +CREATE TABLE `sys_log` ( + `log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `description` varchar(255) DEFAULT NULL, + `log_type` varchar(255) DEFAULT NULL, + `method` varchar(255) DEFAULT NULL, + `params` text DEFAULT NULL, + `request_ip` varchar(255) DEFAULT NULL, + `time` bigint(20) DEFAULT NULL, + `username` varchar(255) DEFAULT NULL, + `address` varchar(255) DEFAULT NULL, + `browser` varchar(255) DEFAULT NULL, + `exception_detail` text DEFAULT NULL, + `create_time` datetime DEFAULT NULL, + PRIMARY KEY (`log_id`) USING BTREE, + KEY `log_create_time_index` (`create_time`), + KEY `inx_log_type` (`log_type`) +) ENGINE=InnoDB AUTO_INCREMENT=3537 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='系统日志'; + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `menu_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `pid` bigint(20) DEFAULT NULL COMMENT '上级菜单ID', + `sub_count` int(5) DEFAULT 0 COMMENT '子菜单数目', + `type` int(11) DEFAULT NULL COMMENT '菜单类型', + `title` varchar(255) DEFAULT NULL COMMENT '菜单标题', + `name` varchar(255) DEFAULT NULL COMMENT '组件名称', + `component` varchar(255) DEFAULT NULL COMMENT '组件', + `menu_sort` int(5) DEFAULT NULL COMMENT '排序', + `icon` varchar(255) DEFAULT NULL COMMENT '图标', + `path` varchar(255) DEFAULT NULL COMMENT '链接地址', + `i_frame` bit(1) DEFAULT NULL COMMENT '是否外链', + `cache` bit(1) DEFAULT b'0' COMMENT '缓存', + `hidden` bit(1) DEFAULT b'0' COMMENT '隐藏', + `permission` varchar(255) DEFAULT NULL COMMENT '权限', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`menu_id`) USING BTREE, + UNIQUE KEY `uniq_title` (`title`), + UNIQUE KEY `uniq_name` (`name`), + KEY `inx_pid` (`pid`) +) ENGINE=InnoDB AUTO_INCREMENT=118 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='系统菜单'; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +BEGIN; +INSERT INTO `sys_menu` VALUES (1, NULL, 7, 0, '系统管理', NULL, NULL, 1, 'system', 'system', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-18 15:11:29', NULL); +INSERT INTO `sys_menu` VALUES (2, 1, 3, 1, '用户管理', 'User', 'system/user/index', 2, 'peoples', 'user', b'0', b'0', b'0', 'user:list', NULL, NULL, '2018-12-18 15:14:44', NULL); +INSERT INTO `sys_menu` VALUES (3, 1, 3, 1, '角色管理', 'Role', 'system/role/index', 3, 'role', 'role', b'0', b'0', b'0', 'roles:list', NULL, NULL, '2018-12-18 15:16:07', NULL); +INSERT INTO `sys_menu` VALUES (5, 1, 3, 1, '菜单管理', 'Menu', 'system/menu/index', 5, 'menu', 'menu', b'0', b'0', b'0', 'menu:list', NULL, NULL, '2018-12-18 15:17:28', NULL); +INSERT INTO `sys_menu` VALUES (6, NULL, 5, 0, '系统监控', NULL, NULL, 10, 'monitor', 'monitor', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-18 15:17:48', NULL); +INSERT INTO `sys_menu` VALUES (7, 6, 0, 1, '操作日志', 'Log', 'monitor/log/index', 11, 'log', 'logs', b'0', b'1', b'0', NULL, NULL, 'admin', '2018-12-18 15:18:26', '2020-06-06 13:11:57'); +INSERT INTO `sys_menu` VALUES (9, 6, 0, 1, 'SQL监控', 'Sql', 'monitor/sql/index', 18, 'sqlMonitor', 'druid', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-18 15:19:34', NULL); +INSERT INTO `sys_menu` VALUES (10, NULL, 5, 0, '组件管理', NULL, NULL, 50, 'zujian', 'components', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-19 13:38:16', NULL); +INSERT INTO `sys_menu` VALUES (11, 10, 0, 1, '图标库', 'Icons', 'components/icons/index', 51, 'icon', 'icon', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-19 13:38:49', NULL); +INSERT INTO `sys_menu` VALUES (14, 36, 0, 1, '邮件工具', 'Email', 'tools/email/index', 35, 'email', 'email', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-27 10:13:09', NULL); +INSERT INTO `sys_menu` VALUES (15, 10, 0, 1, '富文本', 'Editor', 'components/Editor', 52, 'fwb', 'tinymce', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-27 11:58:25', NULL); +INSERT INTO `sys_menu` VALUES (18, 36, 3, 1, '存储管理', 'Storage', 'tools/storage/index', 34, 'qiniu', 'storage', b'0', b'0', b'0', 'storage:list', NULL, NULL, '2018-12-31 11:12:15', NULL); +INSERT INTO `sys_menu` VALUES (19, 36, 0, 1, '支付宝工具', 'AliPay', 'tools/aliPay/index', 37, 'alipay', 'aliPay', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-31 14:52:38', NULL); +INSERT INTO `sys_menu` VALUES (21, NULL, 2, 0, '多级菜单', NULL, '', 900, 'menu', 'nested', b'0', b'0', b'0', NULL, NULL, 'admin', '2019-01-04 16:22:03', '2020-06-21 17:27:35'); +INSERT INTO `sys_menu` VALUES (22, 21, 2, 0, '二级菜单1', NULL, '', 999, 'menu', 'menu1', b'0', b'0', b'0', NULL, NULL, 'admin', '2019-01-04 16:23:29', '2020-06-21 17:27:20'); +INSERT INTO `sys_menu` VALUES (23, 21, 0, 1, '二级菜单2', NULL, 'nested/menu2/index', 999, 'menu', 'menu2', b'0', b'0', b'0', NULL, NULL, NULL, '2019-01-04 16:23:57', NULL); +INSERT INTO `sys_menu` VALUES (24, 22, 0, 1, '三级菜单1', 'Test', 'nested/menu1/menu1-1', 999, 'menu', 'menu1-1', b'0', b'0', b'0', NULL, NULL, NULL, '2019-01-04 16:24:48', NULL); +INSERT INTO `sys_menu` VALUES (27, 22, 0, 1, '三级菜单2', NULL, 'nested/menu1/menu1-2', 999, 'menu', 'menu1-2', b'0', b'0', b'0', NULL, NULL, NULL, '2019-01-07 17:27:32', NULL); +INSERT INTO `sys_menu` VALUES (28, 1, 3, 1, '任务调度', 'Timing', 'system/timing/index', 999, 'timing', 'timing', b'0', b'0', b'0', 'timing:list', NULL, NULL, '2019-01-07 20:34:40', NULL); +INSERT INTO `sys_menu` VALUES (30, 36, 0, 1, '代码生成', 'GeneratorIndex', 'generator/index', 32, 'dev', 'generator', b'0', b'1', b'0', NULL, NULL, NULL, '2019-01-11 15:45:55', NULL); +INSERT INTO `sys_menu` VALUES (32, 6, 0, 1, '异常日志', 'ErrorLog', 'monitor/log/errorLog', 12, 'error', 'errorLog', b'0', b'0', b'0', NULL, NULL, NULL, '2019-01-13 13:49:03', NULL); +INSERT INTO `sys_menu` VALUES (33, 10, 0, 1, 'Markdown', 'Markdown', 'components/MarkDown', 53, 'markdown', 'markdown', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-08 13:46:44', NULL); +INSERT INTO `sys_menu` VALUES (34, 10, 0, 1, 'Yaml编辑器', 'YamlEdit', 'components/YamlEdit', 54, 'dev', 'yaml', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-08 15:49:40', NULL); +INSERT INTO `sys_menu` VALUES (35, 1, 3, 1, '部门管理', 'Dept', 'system/dept/index', 6, 'dept', 'dept', b'0', b'0', b'0', 'dept:list', NULL, NULL, '2019-03-25 09:46:00', NULL); +INSERT INTO `sys_menu` VALUES (36, NULL, 7, 0, '系统工具', NULL, '', 30, 'sys-tools', 'sys-tools', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-29 10:57:35', NULL); +INSERT INTO `sys_menu` VALUES (37, 1, 3, 1, '岗位管理', 'Job', 'system/job/index', 7, 'Steve-Jobs', 'job', b'0', b'0', b'0', 'job:list', NULL, NULL, '2019-03-29 13:51:18', NULL); +INSERT INTO `sys_menu` VALUES (38, 36, 0, 1, '接口文档', 'Swagger', 'tools/swagger/index', 36, 'swagger', 'swagger2', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-29 19:57:53', NULL); +INSERT INTO `sys_menu` VALUES (39, 1, 3, 1, '字典管理', 'Dict', 'system/dict/index', 8, 'dictionary', 'dict', b'0', b'0', b'0', 'dict:list', NULL, NULL, '2019-04-10 11:49:04', NULL); +INSERT INTO `sys_menu` VALUES (41, 6, 0, 1, '在线用户', 'OnlineUser', 'monitor/online/index', 10, 'Steve-Jobs', 'online', b'0', b'0', b'0', NULL, NULL, NULL, '2019-10-26 22:08:43', NULL); +INSERT INTO `sys_menu` VALUES (44, 2, 0, 2, '用户新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'user:add', NULL, NULL, '2019-10-29 10:59:46', NULL); +INSERT INTO `sys_menu` VALUES (45, 2, 0, 2, '用户编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'user:edit', NULL, NULL, '2019-10-29 11:00:08', NULL); +INSERT INTO `sys_menu` VALUES (46, 2, 0, 2, '用户删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'user:del', NULL, NULL, '2019-10-29 11:00:23', NULL); +INSERT INTO `sys_menu` VALUES (48, 3, 0, 2, '角色创建', NULL, '', 2, '', '', b'0', b'0', b'0', 'roles:add', NULL, NULL, '2019-10-29 12:45:34', NULL); +INSERT INTO `sys_menu` VALUES (49, 3, 0, 2, '角色修改', NULL, '', 3, '', '', b'0', b'0', b'0', 'roles:edit', NULL, NULL, '2019-10-29 12:46:16', NULL); +INSERT INTO `sys_menu` VALUES (50, 3, 0, 2, '角色删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'roles:del', NULL, NULL, '2019-10-29 12:46:51', NULL); +INSERT INTO `sys_menu` VALUES (52, 5, 0, 2, '菜单新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'menu:add', NULL, NULL, '2019-10-29 12:55:07', NULL); +INSERT INTO `sys_menu` VALUES (53, 5, 0, 2, '菜单编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'menu:edit', NULL, NULL, '2019-10-29 12:55:40', NULL); +INSERT INTO `sys_menu` VALUES (54, 5, 0, 2, '菜单删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'menu:del', NULL, NULL, '2019-10-29 12:56:00', NULL); +INSERT INTO `sys_menu` VALUES (56, 35, 0, 2, '部门新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'dept:add', NULL, NULL, '2019-10-29 12:57:09', NULL); +INSERT INTO `sys_menu` VALUES (57, 35, 0, 2, '部门编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'dept:edit', NULL, NULL, '2019-10-29 12:57:27', NULL); +INSERT INTO `sys_menu` VALUES (58, 35, 0, 2, '部门删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'dept:del', NULL, NULL, '2019-10-29 12:57:41', NULL); +INSERT INTO `sys_menu` VALUES (60, 37, 0, 2, '岗位新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'job:add', NULL, NULL, '2019-10-29 12:58:27', NULL); +INSERT INTO `sys_menu` VALUES (61, 37, 0, 2, '岗位编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'job:edit', NULL, NULL, '2019-10-29 12:58:45', NULL); +INSERT INTO `sys_menu` VALUES (62, 37, 0, 2, '岗位删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'job:del', NULL, NULL, '2019-10-29 12:59:04', NULL); +INSERT INTO `sys_menu` VALUES (64, 39, 0, 2, '字典新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'dict:add', NULL, NULL, '2019-10-29 13:00:17', NULL); +INSERT INTO `sys_menu` VALUES (65, 39, 0, 2, '字典编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'dict:edit', NULL, NULL, '2019-10-29 13:00:42', NULL); +INSERT INTO `sys_menu` VALUES (66, 39, 0, 2, '字典删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'dict:del', NULL, NULL, '2019-10-29 13:00:59', NULL); +INSERT INTO `sys_menu` VALUES (73, 28, 0, 2, '任务新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'timing:add', NULL, NULL, '2019-10-29 13:07:28', NULL); +INSERT INTO `sys_menu` VALUES (74, 28, 0, 2, '任务编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'timing:edit', NULL, NULL, '2019-10-29 13:07:41', NULL); +INSERT INTO `sys_menu` VALUES (75, 28, 0, 2, '任务删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'timing:del', NULL, NULL, '2019-10-29 13:07:54', NULL); +INSERT INTO `sys_menu` VALUES (77, 18, 0, 2, '上传文件', NULL, '', 2, '', '', b'0', b'0', b'0', 'storage:add', NULL, NULL, '2019-10-29 13:09:09', NULL); +INSERT INTO `sys_menu` VALUES (78, 18, 0, 2, '文件编辑', NULL, '', 3, '', '', b'0', b'0', b'0', 'storage:edit', NULL, NULL, '2019-10-29 13:09:22', NULL); +INSERT INTO `sys_menu` VALUES (79, 18, 0, 2, '文件删除', NULL, '', 4, '', '', b'0', b'0', b'0', 'storage:del', NULL, NULL, '2019-10-29 13:09:34', NULL); +INSERT INTO `sys_menu` VALUES (80, 6, 0, 1, '服务监控', 'ServerMonitor', 'monitor/server/index', 14, 'codeConsole', 'server', b'0', b'0', b'0', 'monitor:list', NULL, 'admin', '2019-11-07 13:06:39', '2020-05-04 18:20:50'); +INSERT INTO `sys_menu` VALUES (82, 36, 0, 1, '生成配置', 'GeneratorConfig', 'generator/config', 33, 'dev', 'generator/config/:tableName', b'0', b'1', b'1', '', NULL, NULL, '2019-11-17 20:08:56', NULL); +INSERT INTO `sys_menu` VALUES (83, 10, 0, 1, '图表库', 'Echarts', 'components/Echarts', 50, 'chart', 'echarts', b'0', b'1', b'0', '', NULL, NULL, '2019-11-21 09:04:32', NULL); +INSERT INTO `sys_menu` VALUES (90, NULL, 5, 1, '运维管理', 'Mnt', '', 20, 'mnt', 'mnt', b'0', b'0', b'0', NULL, NULL, NULL, '2019-11-09 10:31:08', NULL); +INSERT INTO `sys_menu` VALUES (92, 90, 3, 1, '服务器', 'ServerDeploy', 'mnt/server/index', 22, 'server', 'mnt/serverDeploy', b'0', b'0', b'0', 'serverDeploy:list', NULL, NULL, '2019-11-10 10:29:25', NULL); +INSERT INTO `sys_menu` VALUES (93, 90, 3, 1, '应用管理', 'App', 'mnt/app/index', 23, 'app', 'mnt/app', b'0', b'0', b'0', 'app:list', NULL, NULL, '2019-11-10 11:05:16', NULL); +INSERT INTO `sys_menu` VALUES (94, 90, 3, 1, '部署管理', 'Deploy', 'mnt/deploy/index', 24, 'deploy', 'mnt/deploy', b'0', b'0', b'0', 'deploy:list', NULL, NULL, '2019-11-10 15:56:55', NULL); +INSERT INTO `sys_menu` VALUES (97, 90, 1, 1, '部署备份', 'DeployHistory', 'mnt/deployHistory/index', 25, 'backup', 'mnt/deployHistory', b'0', b'0', b'0', 'deployHistory:list', NULL, NULL, '2019-11-10 16:49:44', NULL); +INSERT INTO `sys_menu` VALUES (98, 90, 3, 1, '数据库管理', 'Database', 'mnt/database/index', 26, 'database', 'mnt/database', b'0', b'0', b'0', 'database:list', NULL, NULL, '2019-11-10 20:40:04', NULL); +INSERT INTO `sys_menu` VALUES (102, 97, 0, 2, '删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'deployHistory:del', NULL, NULL, '2019-11-17 09:32:48', NULL); +INSERT INTO `sys_menu` VALUES (103, 92, 0, 2, '服务器新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'serverDeploy:add', NULL, NULL, '2019-11-17 11:08:33', NULL); +INSERT INTO `sys_menu` VALUES (104, 92, 0, 2, '服务器编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'serverDeploy:edit', NULL, NULL, '2019-11-17 11:08:57', NULL); +INSERT INTO `sys_menu` VALUES (105, 92, 0, 2, '服务器删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'serverDeploy:del', NULL, NULL, '2019-11-17 11:09:15', NULL); +INSERT INTO `sys_menu` VALUES (106, 93, 0, 2, '应用新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'app:add', NULL, NULL, '2019-11-17 11:10:03', NULL); +INSERT INTO `sys_menu` VALUES (107, 93, 0, 2, '应用编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'app:edit', NULL, NULL, '2019-11-17 11:10:28', NULL); +INSERT INTO `sys_menu` VALUES (108, 93, 0, 2, '应用删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'app:del', NULL, NULL, '2019-11-17 11:10:55', NULL); +INSERT INTO `sys_menu` VALUES (109, 94, 0, 2, '部署新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'deploy:add', NULL, NULL, '2019-11-17 11:11:22', NULL); +INSERT INTO `sys_menu` VALUES (110, 94, 0, 2, '部署编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'deploy:edit', NULL, NULL, '2019-11-17 11:11:41', NULL); +INSERT INTO `sys_menu` VALUES (111, 94, 0, 2, '部署删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'deploy:del', NULL, NULL, '2019-11-17 11:12:01', NULL); +INSERT INTO `sys_menu` VALUES (112, 98, 0, 2, '数据库新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'database:add', NULL, NULL, '2019-11-17 11:12:43', NULL); +INSERT INTO `sys_menu` VALUES (113, 98, 0, 2, '数据库编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'database:edit', NULL, NULL, '2019-11-17 11:12:58', NULL); +INSERT INTO `sys_menu` VALUES (114, 98, 0, 2, '数据库删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'database:del', NULL, NULL, '2019-11-17 11:13:14', NULL); +INSERT INTO `sys_menu` VALUES (116, 36, 0, 1, '生成预览', 'Preview', 'generator/preview', 999, 'java', 'generator/preview/:tableName', b'0', b'1', b'1', NULL, NULL, NULL, '2019-11-26 14:54:36', NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_quartz_job +-- ---------------------------- +DROP TABLE IF EXISTS `sys_quartz_job`; +CREATE TABLE `sys_quartz_job` ( + `job_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `bean_name` varchar(255) DEFAULT NULL COMMENT 'Spring Bean名称', + `cron_expression` varchar(255) DEFAULT NULL COMMENT 'cron 表达式', + `is_pause` bit(1) DEFAULT NULL COMMENT '状态:1暂停、0启用', + `job_name` varchar(255) DEFAULT NULL COMMENT '任务名称', + `method_name` varchar(255) DEFAULT NULL COMMENT '方法名称', + `params` varchar(255) DEFAULT NULL COMMENT '参数', + `description` varchar(255) DEFAULT NULL COMMENT '备注', + `person_in_charge` varchar(100) DEFAULT NULL COMMENT '负责人', + `email` varchar(100) DEFAULT NULL COMMENT '报警邮箱', + `sub_task` varchar(100) DEFAULT NULL COMMENT '子任务ID', + `pause_after_failure` bit(1) DEFAULT NULL COMMENT '任务失败后是否暂停', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`job_id`) USING BTREE, + KEY `inx_is_pause` (`is_pause`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='定时任务'; + +-- ---------------------------- +-- Records of sys_quartz_job +-- ---------------------------- +BEGIN; +INSERT INTO `sys_quartz_job` VALUES (2, 'testTask', '0/5 * * * * ?', b'1', '测试1', 'run1', 'test', '带参测试,多参使用json', '测试', NULL, NULL, NULL, NULL, 'admin', '2019-08-22 14:08:29', '2020-05-24 13:58:33'); +INSERT INTO `sys_quartz_job` VALUES (3, 'testTask', '0/5 * * * * ?', b'1', '测试', 'run', '', '不带参测试', 'Zheng Jie', '', '5,6', b'1', NULL, 'admin', '2019-09-26 16:44:39', '2020-05-24 14:48:12'); +INSERT INTO `sys_quartz_job` VALUES (5, 'Test', '0/5 * * * * ?', b'1', '任务告警测试', 'run', NULL, '测试', 'test', '', NULL, b'1', 'admin', 'admin', '2020-05-05 20:32:41', '2020-05-05 20:36:13'); +INSERT INTO `sys_quartz_job` VALUES (6, 'testTask', '0/5 * * * * ?', b'1', '测试3', 'run2', NULL, '测试3', 'Zheng Jie', '', NULL, b'1', 'admin', 'admin', '2020-05-05 20:35:41', '2020-05-05 20:36:07'); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_quartz_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_quartz_log`; +CREATE TABLE `sys_quartz_log` ( + `log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `bean_name` varchar(255) DEFAULT NULL, + `create_time` datetime DEFAULT NULL, + `cron_expression` varchar(255) DEFAULT NULL, + `exception_detail` text DEFAULT NULL, + `is_success` bit(1) DEFAULT NULL, + `job_name` varchar(255) DEFAULT NULL, + `method_name` varchar(255) DEFAULT NULL, + `params` varchar(255) DEFAULT NULL, + `time` bigint(20) DEFAULT NULL, + PRIMARY KEY (`log_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=151 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='定时任务日志'; + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `name` varchar(255) NOT NULL COMMENT '名称', + `level` int(255) DEFAULT NULL COMMENT '角色级别', + `description` varchar(255) DEFAULT NULL COMMENT '描述', + `data_scope` varchar(255) DEFAULT NULL COMMENT '数据权限', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`role_id`) USING BTREE, + UNIQUE KEY `uniq_name` (`name`), + KEY `role_name_index` (`name`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='角色表'; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +BEGIN; +INSERT INTO `sys_role` VALUES (1, '超级管理员', 1, '-', '全部', NULL, 'admin', '2018-11-23 11:04:37', '2020-08-06 16:10:24'); +INSERT INTO `sys_role` VALUES (2, '普通用户', 2, '-', '本级', NULL, 'admin', '2018-11-23 13:09:06', '2020-09-05 10:45:12'); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_roles_depts +-- ---------------------------- +DROP TABLE IF EXISTS `sys_roles_depts`; +CREATE TABLE `sys_roles_depts` ( + `role_id` bigint(20) NOT NULL, + `dept_id` bigint(20) NOT NULL, + PRIMARY KEY (`role_id`,`dept_id`) USING BTREE, + KEY `FK7qg6itn5ajdoa9h9o78v9ksur` (`dept_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='角色部门关联'; + +-- ---------------------------- +-- Table structure for sys_roles_menus +-- ---------------------------- +DROP TABLE IF EXISTS `sys_roles_menus`; +CREATE TABLE `sys_roles_menus` ( + `menu_id` bigint(20) NOT NULL COMMENT '菜单ID', + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + PRIMARY KEY (`menu_id`,`role_id`) USING BTREE, + KEY `FKcngg2qadojhi3a651a5adkvbq` (`role_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='角色菜单关联'; + +-- ---------------------------- +-- Records of sys_roles_menus +-- ---------------------------- +BEGIN; +INSERT INTO `sys_roles_menus` VALUES (1, 1); +INSERT INTO `sys_roles_menus` VALUES (2, 1); +INSERT INTO `sys_roles_menus` VALUES (3, 1); +INSERT INTO `sys_roles_menus` VALUES (5, 1); +INSERT INTO `sys_roles_menus` VALUES (6, 1); +INSERT INTO `sys_roles_menus` VALUES (7, 1); +INSERT INTO `sys_roles_menus` VALUES (9, 1); +INSERT INTO `sys_roles_menus` VALUES (10, 1); +INSERT INTO `sys_roles_menus` VALUES (11, 1); +INSERT INTO `sys_roles_menus` VALUES (14, 1); +INSERT INTO `sys_roles_menus` VALUES (15, 1); +INSERT INTO `sys_roles_menus` VALUES (18, 1); +INSERT INTO `sys_roles_menus` VALUES (19, 1); +INSERT INTO `sys_roles_menus` VALUES (21, 1); +INSERT INTO `sys_roles_menus` VALUES (22, 1); +INSERT INTO `sys_roles_menus` VALUES (23, 1); +INSERT INTO `sys_roles_menus` VALUES (24, 1); +INSERT INTO `sys_roles_menus` VALUES (27, 1); +INSERT INTO `sys_roles_menus` VALUES (28, 1); +INSERT INTO `sys_roles_menus` VALUES (30, 1); +INSERT INTO `sys_roles_menus` VALUES (32, 1); +INSERT INTO `sys_roles_menus` VALUES (33, 1); +INSERT INTO `sys_roles_menus` VALUES (34, 1); +INSERT INTO `sys_roles_menus` VALUES (35, 1); +INSERT INTO `sys_roles_menus` VALUES (36, 1); +INSERT INTO `sys_roles_menus` VALUES (37, 1); +INSERT INTO `sys_roles_menus` VALUES (38, 1); +INSERT INTO `sys_roles_menus` VALUES (39, 1); +INSERT INTO `sys_roles_menus` VALUES (41, 1); +INSERT INTO `sys_roles_menus` VALUES (44, 1); +INSERT INTO `sys_roles_menus` VALUES (45, 1); +INSERT INTO `sys_roles_menus` VALUES (46, 1); +INSERT INTO `sys_roles_menus` VALUES (48, 1); +INSERT INTO `sys_roles_menus` VALUES (49, 1); +INSERT INTO `sys_roles_menus` VALUES (50, 1); +INSERT INTO `sys_roles_menus` VALUES (52, 1); +INSERT INTO `sys_roles_menus` VALUES (53, 1); +INSERT INTO `sys_roles_menus` VALUES (54, 1); +INSERT INTO `sys_roles_menus` VALUES (56, 1); +INSERT INTO `sys_roles_menus` VALUES (57, 1); +INSERT INTO `sys_roles_menus` VALUES (58, 1); +INSERT INTO `sys_roles_menus` VALUES (60, 1); +INSERT INTO `sys_roles_menus` VALUES (61, 1); +INSERT INTO `sys_roles_menus` VALUES (62, 1); +INSERT INTO `sys_roles_menus` VALUES (64, 1); +INSERT INTO `sys_roles_menus` VALUES (65, 1); +INSERT INTO `sys_roles_menus` VALUES (66, 1); +INSERT INTO `sys_roles_menus` VALUES (73, 1); +INSERT INTO `sys_roles_menus` VALUES (74, 1); +INSERT INTO `sys_roles_menus` VALUES (75, 1); +INSERT INTO `sys_roles_menus` VALUES (77, 1); +INSERT INTO `sys_roles_menus` VALUES (78, 1); +INSERT INTO `sys_roles_menus` VALUES (79, 1); +INSERT INTO `sys_roles_menus` VALUES (80, 1); +INSERT INTO `sys_roles_menus` VALUES (82, 1); +INSERT INTO `sys_roles_menus` VALUES (83, 1); +INSERT INTO `sys_roles_menus` VALUES (90, 1); +INSERT INTO `sys_roles_menus` VALUES (92, 1); +INSERT INTO `sys_roles_menus` VALUES (93, 1); +INSERT INTO `sys_roles_menus` VALUES (94, 1); +INSERT INTO `sys_roles_menus` VALUES (97, 1); +INSERT INTO `sys_roles_menus` VALUES (98, 1); +INSERT INTO `sys_roles_menus` VALUES (102, 1); +INSERT INTO `sys_roles_menus` VALUES (103, 1); +INSERT INTO `sys_roles_menus` VALUES (104, 1); +INSERT INTO `sys_roles_menus` VALUES (105, 1); +INSERT INTO `sys_roles_menus` VALUES (106, 1); +INSERT INTO `sys_roles_menus` VALUES (107, 1); +INSERT INTO `sys_roles_menus` VALUES (108, 1); +INSERT INTO `sys_roles_menus` VALUES (109, 1); +INSERT INTO `sys_roles_menus` VALUES (110, 1); +INSERT INTO `sys_roles_menus` VALUES (111, 1); +INSERT INTO `sys_roles_menus` VALUES (112, 1); +INSERT INTO `sys_roles_menus` VALUES (113, 1); +INSERT INTO `sys_roles_menus` VALUES (114, 1); +INSERT INTO `sys_roles_menus` VALUES (116, 1); +INSERT INTO `sys_roles_menus` VALUES (120, 1); +INSERT INTO `sys_roles_menus` VALUES (1, 2); +INSERT INTO `sys_roles_menus` VALUES (2, 2); +INSERT INTO `sys_roles_menus` VALUES (6, 2); +INSERT INTO `sys_roles_menus` VALUES (7, 2); +INSERT INTO `sys_roles_menus` VALUES (9, 2); +INSERT INTO `sys_roles_menus` VALUES (10, 2); +INSERT INTO `sys_roles_menus` VALUES (11, 2); +INSERT INTO `sys_roles_menus` VALUES (14, 2); +INSERT INTO `sys_roles_menus` VALUES (15, 2); +INSERT INTO `sys_roles_menus` VALUES (19, 2); +INSERT INTO `sys_roles_menus` VALUES (21, 2); +INSERT INTO `sys_roles_menus` VALUES (22, 2); +INSERT INTO `sys_roles_menus` VALUES (23, 2); +INSERT INTO `sys_roles_menus` VALUES (24, 2); +INSERT INTO `sys_roles_menus` VALUES (27, 2); +INSERT INTO `sys_roles_menus` VALUES (30, 2); +INSERT INTO `sys_roles_menus` VALUES (32, 2); +INSERT INTO `sys_roles_menus` VALUES (33, 2); +INSERT INTO `sys_roles_menus` VALUES (34, 2); +INSERT INTO `sys_roles_menus` VALUES (36, 2); +INSERT INTO `sys_roles_menus` VALUES (80, 2); +INSERT INTO `sys_roles_menus` VALUES (82, 2); +INSERT INTO `sys_roles_menus` VALUES (83, 2); +INSERT INTO `sys_roles_menus` VALUES (116, 2); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `dept_id` bigint(20) DEFAULT NULL COMMENT '部门名称', + `username` varchar(255) DEFAULT NULL COMMENT '用户名', + `nick_name` varchar(255) DEFAULT NULL COMMENT '昵称', + `gender` varchar(2) DEFAULT NULL COMMENT '性别', + `phone` varchar(255) DEFAULT NULL COMMENT '手机号码', + `email` varchar(255) DEFAULT NULL COMMENT '邮箱', + `avatar_name` varchar(255) DEFAULT NULL COMMENT '头像地址', + `avatar_path` varchar(255) DEFAULT NULL COMMENT '头像真实路径', + `password` varchar(255) DEFAULT NULL COMMENT '密码', + `is_admin` bit(1) DEFAULT b'0' COMMENT '是否为admin账号', + `enabled` bigint(20) DEFAULT NULL COMMENT '状态:1启用、0禁用', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `pwd_reset_time` datetime DEFAULT NULL COMMENT '修改密码的时间', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`user_id`) USING BTREE, + UNIQUE KEY `UK_kpubos9gc2cvtkb0thktkbkes` (`email`) USING BTREE, + UNIQUE KEY `username` (`username`) USING BTREE, + UNIQUE KEY `uniq_username` (`username`), + UNIQUE KEY `uniq_email` (`email`), + KEY `FK5rwmryny6jthaaxkogownknqp` (`dept_id`) USING BTREE, + KEY `FKpq2dhypk2qgt68nauh2by22jb` (`avatar_name`) USING BTREE, + KEY `inx_enabled` (`enabled`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='系统用户'; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +BEGIN; +INSERT INTO `sys_user` VALUES (1, 2, 'admin', '管理员', '男', '18888888888', '[email protected]', 'avatar-20200806032259161.png', '/Users/jie/Documents/work/me/admin/dns/~/avatar/avatar-20200806032259161.png', '$2a$10$Egp1/gvFlt7zhlXVfEFw4OfWQCGPw0ClmMcc6FjTnvXNRVf9zdMRa', b'1', 1, NULL, 'admin', '2020-05-03 16:38:31', '2018-08-23 09:11:56', '2020-09-05 10:43:31'); +INSERT INTO `sys_user` VALUES (2, 2, 'test', '测试', '男', '19999999999', '[email protected]', NULL, NULL, '$2a$10$4XcyudOYTSz6fue6KFNMHeUQnCX5jbBQypLEnGk1PmekXt5c95JcK', b'0', 1, 'admin', 'admin', NULL, '2020-05-05 11:15:49', '2020-09-05 10:43:38'); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_users_jobs +-- ---------------------------- +DROP TABLE IF EXISTS `sys_users_jobs`; +CREATE TABLE `sys_users_jobs` ( + `user_id` bigint(20) NOT NULL COMMENT '用户ID', + `job_id` bigint(20) NOT NULL COMMENT '岗位ID', + PRIMARY KEY (`user_id`,`job_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ---------------------------- +-- Records of sys_users_jobs +-- ---------------------------- +BEGIN; +INSERT INTO `sys_users_jobs` VALUES (1, 11); +INSERT INTO `sys_users_jobs` VALUES (2, 12); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_users_roles +-- ---------------------------- +DROP TABLE IF EXISTS `sys_users_roles`; +CREATE TABLE `sys_users_roles` ( + `user_id` bigint(20) NOT NULL COMMENT '用户ID', + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + PRIMARY KEY (`user_id`,`role_id`) USING BTREE, + KEY `FKq4eq273l04bpu4efj0jd0jb98` (`role_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='用户角色关联'; + +-- ---------------------------- +-- Records of sys_users_roles +-- ---------------------------- +BEGIN; +INSERT INTO `sys_users_roles` VALUES (1, 1); +INSERT INTO `sys_users_roles` VALUES (2, 2); +COMMIT; + +-- ---------------------------- +-- Table structure for tool_alipay_config +-- ---------------------------- +DROP TABLE IF EXISTS `tool_alipay_config`; +CREATE TABLE `tool_alipay_config` ( + `config_id` bigint(20) NOT NULL COMMENT 'ID', + `app_id` varchar(255) DEFAULT NULL COMMENT '应用ID', + `charset` varchar(255) DEFAULT NULL COMMENT '编码', + `format` varchar(255) DEFAULT NULL COMMENT '类型 固定格式json', + `gateway_url` varchar(255) DEFAULT NULL COMMENT '网关地址', + `notify_url` varchar(255) DEFAULT NULL COMMENT '异步回调', + `private_key` text DEFAULT NULL COMMENT '私钥', + `public_key` text DEFAULT NULL COMMENT '公钥', + `return_url` varchar(255) DEFAULT NULL COMMENT '回调地址', + `sign_type` varchar(255) DEFAULT NULL COMMENT '签名方式', + `sys_service_provider_id` varchar(255) DEFAULT NULL COMMENT '商户号', + PRIMARY KEY (`config_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='支付宝配置类'; + +-- ---------------------------- +-- Records of tool_alipay_config +-- ---------------------------- +BEGIN; +INSERT INTO `tool_alipay_config` VALUES (1, '2016091700532697', 'utf-8', 'JSON', 'https://openapi.alipaydev.com/gateway.do', 'http://api.auauz.net/api/aliPay/notify', 'MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC5js8sInU10AJ0cAQ8UMMyXrQ+oHZEkVt5lBwsStmTJ7YikVYgbskx1YYEXTojRsWCb+SH/kDmDU4pK/u91SJ4KFCRMF2411piYuXU/jF96zKrADznYh/zAraqT6hvAIVtQAlMHN53nx16rLzZ/8jDEkaSwT7+HvHiS+7sxSojnu/3oV7BtgISoUNstmSe8WpWHOaWv19xyS+Mce9MY4BfseFhzTICUymUQdd/8hXA28/H6osUfAgsnxAKv7Wil3aJSgaJczWuflYOve0dJ3InZkhw5Cvr0atwpk8YKBQjy5CdkoHqvkOcIB+cYHXJKzOE5tqU7inSwVbHzOLQ3XbnAgMBAAECggEAVJp5eT0Ixg1eYSqFs9568WdetUNCSUchNxDBu6wxAbhUgfRUGZuJnnAll63OCTGGck+EGkFh48JjRcBpGoeoHLL88QXlZZbC/iLrea6gcDIhuvfzzOffe1RcZtDFEj9hlotg8dQj1tS0gy9pN9g4+EBH7zeu+fyv+qb2e/v1l6FkISXUjpkD7RLQr3ykjiiEw9BpeKb7j5s7Kdx1NNIzhkcQKNqlk8JrTGDNInbDM6inZfwwIO2R1DHinwdfKWkvOTODTYa2MoAvVMFT9Bec9FbLpoWp7ogv1JMV9svgrcF9XLzANZ/OQvkbe9TV9GWYvIbxN6qwQioKCWO4GPnCAQKBgQDgW5MgfhX8yjXqoaUy/d1VjI8dHeIyw8d+OBAYwaxRSlCfyQ+tieWcR2HdTzPca0T0GkWcKZm0ei5xRURgxt4DUDLXNh26HG0qObbtLJdu/AuBUuCqgOiLqJ2f1uIbrz6OZUHns+bT/jGW2Ws8+C13zTCZkZt9CaQsrp3QOGDx5wKBgQDTul39hp3ZPwGNFeZdkGoUoViOSd5Lhowd5wYMGAEXWRLlU8z+smT5v0POz9JnIbCRchIY2FAPKRdVTICzmPk2EPJFxYTcwaNbVqL6lN7J2IlXXMiit5QbiLauo55w7plwV6LQmKm9KV7JsZs5XwqF7CEovI7GevFzyD3w+uizAQKBgC3LY1eRhOlpWOIAhpjG6qOoohmeXOphvdmMlfSHq6WYFqbWwmV4rS5d/6LNpNdL6fItXqIGd8I34jzql49taCmi+A2nlR/E559j0mvM20gjGDIYeZUz5MOE8k+K6/IcrhcgofgqZ2ZED1ksHdB/E8DNWCswZl16V1FrfvjeWSNnAoGAMrBplCrIW5xz+J0Hm9rZKrs+AkK5D4fUv8vxbK/KgxZ2KaUYbNm0xv39c+PZUYuFRCz1HDGdaSPDTE6WeWjkMQd5mS6ikl9hhpqFRkyh0d0fdGToO9yLftQKOGE/q3XUEktI1XvXF0xyPwNgUCnq0QkpHyGVZPtGFxwXiDvpvgECgYA5PoB+nY8iDiRaJNko9w0hL4AeKogwf+4TbCw+KWVEn6jhuJa4LFTdSqp89PktQaoVpwv92el/AhYjWOl/jVCm122f9b7GyoelbjMNolToDwe5pF5RnSpEuDdLy9MfE8LnE3PlbE7E5BipQ3UjSebkgNboLHH/lNZA5qvEtvbfvQ==', 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAut9evKRuHJ/2QNfDlLwvN/S8l9hRAgPbb0u61bm4AtzaTGsLeMtScetxTWJnVvAVpMS9luhEJjt+Sbk5TNLArsgzzwARgaTKOLMT1TvWAK5EbHyI+eSrc3s7Awe1VYGwcubRFWDm16eQLv0k7iqiw+4mweHSz/wWyvBJVgwLoQ02btVtAQErCfSJCOmt0Q/oJQjj08YNRV4EKzB19+f5A+HQVAKy72dSybTzAK+3FPtTtNen/+b5wGeat7c32dhYHnGorPkPeXLtsqqUTp1su5fMfd4lElNdZaoCI7osZxWWUo17vBCZnyeXc9fk0qwD9mK6yRAxNbrY72Xx5VqIqwIDAQAB', 'http://api.auauz.net/api/aliPay/return', 'RSA2', '2088102176044281'); +COMMIT; + +-- ---------------------------- +-- Table structure for tool_email_config +-- ---------------------------- +DROP TABLE IF EXISTS `tool_email_config`; +CREATE TABLE `tool_email_config` ( + `config_id` bigint(20) NOT NULL COMMENT 'ID', + `from_user` varchar(255) DEFAULT NULL COMMENT '收件人', + `host` varchar(255) DEFAULT NULL COMMENT '邮件服务器SMTP地址', + `pass` varchar(255) DEFAULT NULL COMMENT '密码', + `port` varchar(255) DEFAULT NULL COMMENT '端口', + `user` varchar(255) DEFAULT NULL COMMENT '发件者用户名', + PRIMARY KEY (`config_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='邮箱配置'; + +-- ---------------------------- +-- Table structure for tool_local_storage +-- ---------------------------- +DROP TABLE IF EXISTS `tool_local_storage`; +CREATE TABLE `tool_local_storage` ( + `storage_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `real_name` varchar(255) DEFAULT NULL COMMENT '文件真实的名称', + `name` varchar(255) DEFAULT NULL COMMENT '文件名', + `suffix` varchar(255) DEFAULT NULL COMMENT '后缀', + `path` varchar(255) DEFAULT NULL COMMENT '路径', + `type` varchar(255) DEFAULT NULL COMMENT '类型', + `size` varchar(100) DEFAULT NULL COMMENT '大小', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建者', + `update_by` varchar(255) DEFAULT NULL COMMENT '更新者', + `create_time` datetime DEFAULT NULL COMMENT '创建日期', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`storage_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='本地存储'; + +-- ---------------------------- +-- Records of tool_local_storage +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for tool_qiniu_config +-- ---------------------------- +DROP TABLE IF EXISTS `tool_qiniu_config`; +CREATE TABLE `tool_qiniu_config` ( + `config_id` bigint(20) NOT NULL COMMENT 'ID', + `access_key` text DEFAULT NULL COMMENT 'accessKey', + `bucket` varchar(255) DEFAULT NULL COMMENT 'Bucket 识别符', + `host` varchar(255) NOT NULL COMMENT '外链域名', + `secret_key` text DEFAULT NULL COMMENT 'secretKey', + `type` varchar(255) DEFAULT NULL COMMENT '空间类型', + `zone` varchar(255) DEFAULT NULL COMMENT '机房', + PRIMARY KEY (`config_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='七牛云配置'; + +-- ---------------------------- +-- Table structure for tool_qiniu_content +-- ---------------------------- +DROP TABLE IF EXISTS `tool_qiniu_content`; +CREATE TABLE `tool_qiniu_content` ( + `content_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `bucket` varchar(255) DEFAULT NULL COMMENT 'Bucket 识别符', + `name` varchar(255) DEFAULT NULL COMMENT '文件名称', + `size` varchar(255) DEFAULT NULL COMMENT '文件大小', + `type` varchar(255) DEFAULT NULL COMMENT '文件类型:私有或公开', + `url` varchar(255) DEFAULT NULL COMMENT '文件url', + `suffix` varchar(255) DEFAULT NULL COMMENT '文件后缀', + `update_time` datetime DEFAULT NULL COMMENT '上传或同步的时间', + PRIMARY KEY (`content_id`) USING BTREE, + UNIQUE KEY `uniq_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='七牛云文件存储'; + +-- ---------------------------- +-- Records of tool_qiniu_content +-- ---------------------------- +BEGIN; +COMMIT; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/UI source code/dns-dev-2.0/sql/tool_picture.sql b/UI source code/dns-dev-2.0/sql/tool_picture.sql new file mode 100644 index 0000000..6b36d0d --- /dev/null +++ b/UI source code/dns-dev-2.0/sql/tool_picture.sql @@ -0,0 +1,2 @@ +-- 删除免费图床表 +DROP TABLE tool_picture;
\ No newline at end of file diff --git a/UI source code/dns-dev-2.0/sql/脚本如何选择.md b/UI source code/dns-dev-2.0/sql/脚本如何选择.md new file mode 100644 index 0000000..9734971 --- /dev/null +++ b/UI source code/dns-dev-2.0/sql/脚本如何选择.md @@ -0,0 +1,11 @@ +## 脚本指南 +项目根目录的 sql 文件夹内提供了本次数据库变更的脚本,脚本如何选择,以及执行的顺序如下 + +::: tip 注意 +操作数据库属于危险行为,请勿用于生产库,请事先做好备份!!! +::: + +### 初次使用 +dns.sql 为 dns 项目完整的 sql 脚本,适合于初次使用的用户 + +### 更新迭代 diff --git a/UI source code/dns_mapping_ui-master/.editorconfig b/UI source code/dns_mapping_ui-master/.editorconfig new file mode 100644 index 0000000..3454886 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/.editorconfig @@ -0,0 +1,14 @@ +# https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/UI source code/dns_mapping_ui-master/.env.development b/UI source code/dns_mapping_ui-master/.env.development new file mode 100644 index 0000000..6ed6b44 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/.env.development @@ -0,0 +1,8 @@ +ENV = 'development' + +# 接口地址 +VUE_APP_BASE_API = 'http://192.168.32.7:8888' +VUE_APP_WS_API = 'ws://192.168.32.7:8888' + +# 是否启用 babel-plugin-dynamic-import-node插件 +VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/UI source code/dns_mapping_ui-master/.env.production b/UI source code/dns_mapping_ui-master/.env.production new file mode 100644 index 0000000..70f3cdc --- /dev/null +++ b/UI source code/dns_mapping_ui-master/.env.production @@ -0,0 +1,7 @@ +ENV = 'production' + +# 如果使用 Nginx 代理后端接口,那么此处需要改为 '/',文件查看 Docker 部署篇,Nginx 配置 +# 接口地址,注意协议,如果你没有配置 ssl,需要将 https 改为 http +VUE_APP_BASE_API = 'http://192.168.10.175:8888' +# 如果接口是 http 形式, wss 需要改为 ws +VUE_APP_WS_API = 'ws://192.168.10.175:8888' diff --git a/UI source code/dns_mapping_ui-master/.eslintignore b/UI source code/dns_mapping_ui-master/.eslintignore new file mode 100644 index 0000000..e6529fc --- /dev/null +++ b/UI source code/dns_mapping_ui-master/.eslintignore @@ -0,0 +1,4 @@ +build/*.js +src/assets +public +dist diff --git a/UI source code/dns_mapping_ui-master/.eslintrc.js b/UI source code/dns_mapping_ui-master/.eslintrc.js new file mode 100644 index 0000000..c977505 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/.eslintrc.js @@ -0,0 +1,198 @@ +module.exports = { + root: true, + parserOptions: { + parser: 'babel-eslint', + sourceType: 'module' + }, + env: { + browser: true, + node: true, + es6: true, + }, + extends: ['plugin:vue/recommended', 'eslint:recommended'], + + // add your custom rules here + //it is base on https://github.com/vuejs/eslint-config-vue + rules: { + "vue/max-attributes-per-line": [2, { + "singleline": 10, + "multiline": { + "max": 1, + "allowFirstLine": false + } + }], + "vue/singleline-html-element-content-newline": "off", + "vue/multiline-html-element-content-newline":"off", + "vue/name-property-casing": ["error", "PascalCase"], + "vue/no-v-html": "off", + 'accessor-pairs': 2, + 'arrow-spacing': [2, { + 'before': true, + 'after': true + }], + 'block-spacing': [2, 'always'], + 'brace-style': [2, '1tbs', { + 'allowSingleLine': true + }], + 'camelcase': [0, { + 'properties': 'always' + }], + 'comma-dangle': [2, 'never'], + 'comma-spacing': [2, { + 'before': false, + 'after': true + }], + 'comma-style': [2, 'last'], + 'constructor-super': 2, + 'curly': [2, 'multi-line'], + 'dot-location': [2, 'property'], + 'eol-last': 2, + 'eqeqeq': ["error", "always", {"null": "ignore"}], + 'generator-star-spacing': [2, { + 'before': true, + 'after': true + }], + 'handle-callback-err': [2, '^(err|error)$'], + 'indent': [2, 2, { + 'SwitchCase': 1 + }], + 'jsx-quotes': [2, 'prefer-single'], + 'key-spacing': [2, { + 'beforeColon': false, + 'afterColon': true + }], + 'keyword-spacing': [2, { + 'before': true, + 'after': true + }], + 'new-cap': [2, { + 'newIsCap': true, + 'capIsNew': false + }], + 'new-parens': 2, + 'no-array-constructor': 2, + 'no-caller': 2, + 'no-console': 'off', + 'no-class-assign': 2, + 'no-cond-assign': 2, + 'no-const-assign': 2, + 'no-control-regex': 0, + 'no-delete-var': 2, + 'no-dupe-args': 2, + 'no-dupe-class-members': 2, + 'no-dupe-keys': 2, + 'no-duplicate-case': 2, + 'no-empty-character-class': 2, + 'no-empty-pattern': 2, + 'no-eval': 2, + 'no-ex-assign': 2, + 'no-extend-native': 2, + 'no-extra-bind': 2, + 'no-extra-boolean-cast': 2, + 'no-extra-parens': [2, 'functions'], + 'no-fallthrough': 2, + 'no-floating-decimal': 2, + 'no-func-assign': 2, + 'no-implied-eval': 2, + 'no-inner-declarations': [2, 'functions'], + 'no-invalid-regexp': 2, + 'no-irregular-whitespace': 2, + 'no-iterator': 2, + 'no-label-var': 2, + 'no-labels': [2, { + 'allowLoop': false, + 'allowSwitch': false + }], + 'no-lone-blocks': 2, + 'no-mixed-spaces-and-tabs': 2, + 'no-multi-spaces': 2, + 'no-multi-str': 2, + 'no-multiple-empty-lines': [2, { + 'max': 1 + }], + 'no-native-reassign': 2, + 'no-negated-in-lhs': 2, + 'no-new-object': 2, + 'no-new-require': 2, + 'no-new-symbol': 2, + 'no-new-wrappers': 2, + 'no-obj-calls': 2, + 'no-octal': 2, + 'no-octal-escape': 2, + 'no-path-concat': 2, + 'no-proto': 2, + 'no-redeclare': 2, + 'no-regex-spaces': 2, + 'no-return-assign': [2, 'except-parens'], + 'no-self-assign': 2, + 'no-self-compare': 2, + 'no-sequences': 2, + 'no-shadow-restricted-names': 2, + 'no-spaced-func': 2, + 'no-sparse-arrays': 2, + 'no-this-before-super': 2, + 'no-throw-literal': 2, + 'no-trailing-spaces': 2, + 'no-undef': 2, + 'no-undef-init': 2, + 'no-unexpected-multiline': 2, + 'no-unmodified-loop-condition': 2, + 'no-unneeded-ternary': [2, { + 'defaultAssignment': false + }], + 'no-unreachable': 2, + 'no-unsafe-finally': 2, + 'no-unused-vars': [2, { + 'vars': 'all', + 'args': 'none' + }], + 'no-useless-call': 2, + 'no-useless-computed-key': 2, + 'no-useless-constructor': 2, + 'no-useless-escape': 0, + 'no-whitespace-before-property': 2, + 'no-with': 2, + 'one-var': [2, { + 'initialized': 'never' + }], + 'operator-linebreak': [2, 'after', { + 'overrides': { + '?': 'before', + ':': 'before' + } + }], + 'padded-blocks': [2, 'never'], + 'quotes': [2, 'single', { + 'avoidEscape': true, + 'allowTemplateLiterals': true + }], + 'semi': [2, 'never'], + 'semi-spacing': [2, { + 'before': false, + 'after': true + }], + 'space-before-blocks': [2, 'always'], + 'space-before-function-paren': [2, 'never'], + 'space-in-parens': [2, 'never'], + 'space-infix-ops': 2, + 'space-unary-ops': [2, { + 'words': true, + 'nonwords': false + }], + 'spaced-comment': [2, 'always', { + 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] + }], + 'template-curly-spacing': [2, 'never'], + 'use-isnan': 2, + 'valid-typeof': 2, + 'wrap-iife': [2, 'any'], + 'yield-star-spacing': [2, 'both'], + 'yoda': [2, 'never'], + 'prefer-const': 2, + 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, + 'object-curly-spacing': [2, 'always', { + objectsInObjects: false + }], + 'array-bracket-spacing': [2, 'never'] + } +} diff --git a/UI source code/dns_mapping_ui-master/.gitignore b/UI source code/dns_mapping_ui-master/.gitignore new file mode 100644 index 0000000..1978bc2 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/.gitignore @@ -0,0 +1,24 @@ +.DS_Store +node_modules/ +dist/ +demo/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +**/*.log + +tests/**/coverage/ +tests/e2e/reports +selenium-debug.log + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.local + +package-lock.json +yarn.lock diff --git a/UI source code/dns_mapping_ui-master/.travis.yml b/UI source code/dns_mapping_ui-master/.travis.yml new file mode 100644 index 0000000..f4be7a0 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: 10 +script: npm run test +notifications: + email: false diff --git a/UI source code/dns_mapping_ui-master/LICENSE b/UI source code/dns_mapping_ui-master/LICENSE new file mode 100644 index 0000000..78a36cb --- /dev/null +++ b/UI source code/dns_mapping_ui-master/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "{}" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright 2019 Zheng Jie + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/UI source code/dns_mapping_ui-master/README.md b/UI source code/dns_mapping_ui-master/README.md new file mode 100644 index 0000000..f835db4 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/README.md @@ -0,0 +1,69 @@ +# ELADMIN-WEB + +ELADMIN 前端源码 + +#### 项目源码 + +| | 后端源码 | 前端源码 | +|--- |--- | --- | +| github | https://github.com/elunez/eladmin | https://github.com/elunez/eladmin-web | +| 码云 | https://gitee.com/elunez/eladmin | https://gitee.com/elunez/eladmin-web | + +#### 开发文档 +[https://el-admin.vip](https://el-admin.vip) + +#### 体验地址 +[https://el-admin.vip/demo](https://el-admin.vip/demo) + +#### 前端模板 + +初始模板基于: [https://github.com/PanJiaChen/vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) + +模板文档: [https://panjiachen.github.io/vue-element-admin-site/zh/guide/](https://panjiachen.github.io/vue-element-admin-site/zh/guide/) + +#### Build Setup +``` bash +# 配置镜像加速 +https://www.ydyno.com/archives/1219.html + +# 安装依赖 +npm install + +# 启动服务 localhost:8013 +npm run dev + +# 构建生产环境 +npm run build:prod +``` + +#### 常见问题 + +1、linux 系统在安装依赖的时候会出现 node-sass 无法安装的问题 + +解决方案: +``` +1. 单独安装:npm install --unsafe-perm node-sass +2. 直接使用:npm install --unsafe-perm +``` + +2、加速node-sass安装 + +https://www.ydyno.com/archives/1219.html + +#### 特别鸣谢 + +- 感谢 [JetBrains](https://www.jetbrains.com/) 提供的非商业开源软件开发授权 + +- 感谢 [PanJiaChen](https://github.com/PanJiaChen/vue-element-admin) 大佬提供的前端模板 + +- 感谢 [Moxun](https://github.com/moxun1639) 大佬提供的前端 Curd 通用组件 + +- 感谢 [zhy6599](https://gitee.com/zhy6599) 大佬提供的后端运维管理相关功能 + +- 感谢 [j.yao.SUSE](https://github.com/everhopingandwaiting) 大佬提供的匿名接口与Redis限流等功能 + +- 感谢 [d15801543974](https://github.com/d15801543974) 大佬提供的基于注解的通用查询方式 + +#### 反馈交流 + +- QQ交流群:一群:891137268、二群:947578238、三群:659622532
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/babel.config.js b/UI source code/dns_mapping_ui-master/babel.config.js new file mode 100644 index 0000000..804632a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/babel.config.js @@ -0,0 +1,11 @@ +const plugins = ['@vue/babel-plugin-transform-vue-jsx'] +// 生产环境移除console +if (process.env.NODE_ENV === 'production') { + plugins.push('transform-remove-console') +} +module.exports = { + plugins: plugins, + presets: [ + '@vue/app' + ] +} diff --git a/UI source code/dns_mapping_ui-master/jest.config.js b/UI source code/dns_mapping_ui-master/jest.config.js new file mode 100644 index 0000000..143cdc8 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/jest.config.js @@ -0,0 +1,24 @@ +module.exports = { + moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], + transform: { + '^.+\\.vue$': 'vue-jest', + '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': + 'jest-transform-stub', + '^.+\\.jsx?$': 'babel-jest' + }, + moduleNameMapper: { + '^@/(.*)$': '<rootDir>/src/$1' + }, + snapshotSerializers: ['jest-serializer-vue'], + testMatch: [ + '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' + ], + collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'], + coverageDirectory: '<rootDir>/tests/unit/coverage', + // 'collectCoverage': true, + 'coverageReporters': [ + 'lcov', + 'text-summary' + ], + testURL: 'http://localhost/' +} diff --git a/UI source code/dns_mapping_ui-master/package.json b/UI source code/dns_mapping_ui-master/package.json new file mode 100644 index 0000000..2a19062 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/package.json @@ -0,0 +1,121 @@ +{ + "name": "eladmin-web", + "version": "2.6.0", + "description": "EL-ADMIN 前端源码", + "author": "Zheng Jie", + "license": "Apache-2.0", + "scripts": { + "dev": "vue-cli-service serve", + "build:prod": "vue-cli-service build", + "build:stage": "vue-cli-service build --mode staging", + "preview": "node build/index.js --preview", + "lint": "eslint --ext .js,.vue src", + "test:unit": "jest --clearCache && vue-cli-service test:unit", + "svgo": "svgo -f src/assets/icons/svg --config=src/assets/icons/svgo.yml", + "new": "plop" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "src/**/*.{js,vue}": [ + "eslint --fix", + "git add" + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/elunez/eladmin-web.git" + }, + "bugs": { + "url": "https://github.com/elunez/eladmin/issues" + }, + "dependencies": { + "@riophae/vue-treeselect": "^0.4.0", + "axios": "^0.21.1", + "clipboard": "2.0.4", + "codemirror": "^5.49.2", + "connect": "3.6.6", + "core-js": "^2.6.12", + "echarts": "^4.2.1", + "echarts-gl": "^1.1.1", + "echarts-wordcloud": "^1.1.3", + "element-ui": "^2.15.6", + "file-saver": "1.3.8", + "fuse.js": "3.4.4", + "install": "^0.13.0", + "js-beautify": "^1.10.2", + "js-cookie": "2.2.0", + "jsencrypt": "^3.0.0-rc.1", + "jszip": "^3.7.1", + "less": "^3.9.0", + "less-loader": "^5.0.0", + "lodash": "^4.17.21", + "mavon-editor": "^2.9.1", + "moment": "^2.29.3", + "normalize.css": "7.0.0", + "nprogress": "0.2.0", + "path-to-regexp": "2.4.0", + "qs": "^6.10.1", + "screenfull": "4.2.0", + "sortablejs": "1.8.4", + "vue": "^2.6.14", + "vue-count-to": "^1.0.13", + "vue-cropper": "0.4.9", + "vue-echarts": "^5.0.0-beta.0", + "vue-highlightjs": "^1.3.3", + "vue-i18n": "^7.3.2", + "vue-image-crop-upload": "^2.5.0", + "vue-router": "3.0.2", + "vue-splitpane": "1.0.4", + "vuedraggable": "2.20.0", + "vuex": "3.1.0", + "wangeditor": "^4.7.11", + "xlsx": "^0.17.4" + }, + "devDependencies": { + "@babel/parser": "^7.7.4", + "@babel/register": "7.0.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.2.1", + "@vue/cli-plugin-babel": "3.5.3", + "@vue/cli-plugin-eslint": "^3.9.1", + "@vue/cli-plugin-unit-jest": "3.5.3", + "@vue/cli-service": "3.5.3", + "@vue/test-utils": "1.0.0-beta.29", + "autoprefixer": "^9.5.1", + "babel-core": "7.0.0-bridge.0", + "babel-eslint": "10.0.1", + "babel-jest": "23.6.0", + "babel-plugin-dynamic-import-node": "2.3.0", + "babel-plugin-transform-remove-console": "^6.9.4", + "chalk": "2.4.2", + "chokidar": "2.1.5", + "connect": "3.6.6", + "eslint": "5.15.3", + "eslint-plugin-vue": "5.2.2", + "html-webpack-plugin": "3.2.0", + "http-proxy-middleware": "^0.19.1", + "husky": "1.3.1", + "lint-staged": "8.1.5", + "plop": "2.3.0", + "sass": "1.32.13", + "sass-loader": "10.2.0", + "script-ext-html-webpack-plugin": "2.1.3", + "script-loader": "0.7.2", + "serve-static": "^1.13.2", + "svg-sprite-loader": "4.1.3", + "svgo": "1.2.0", + "tasksfile": "^5.1.1", + "vue-template-compiler": "2.6.14" + }, + "engines": { + "node": ">=8.9", + "npm": ">= 3.0.0" + }, + "browserslist": [ + "> 1%", + "last 2 versions" + ] +} diff --git a/UI source code/dns_mapping_ui-master/plopfile.js b/UI source code/dns_mapping_ui-master/plopfile.js new file mode 100644 index 0000000..9f3147e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/plopfile.js @@ -0,0 +1,7 @@ +const viewGenerator = require('./plop-templates/view/prompt') +const componentGenerator = require('./plop-templates/component/prompt') + +module.exports = function(plop) { + plop.setGenerator('view', viewGenerator) + plop.setGenerator('component', componentGenerator) +} diff --git a/UI source code/dns_mapping_ui-master/postcss.config.js b/UI source code/dns_mapping_ui-master/postcss.config.js new file mode 100644 index 0000000..961986e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + autoprefixer: {} + } +} diff --git a/UI source code/dns_mapping_ui-master/public/favicon.ico b/UI source code/dns_mapping_ui-master/public/favicon.ico Binary files differnew file mode 100644 index 0000000..fcb6999 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/public/favicon.ico diff --git a/UI source code/dns_mapping_ui-master/public/index.html b/UI source code/dns_mapping_ui-master/public/index.html new file mode 100644 index 0000000..e918500 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/public/index.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> + <meta name="renderer" content="webkit"> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> + <link rel="icon" href="<%= BASE_URL %>favicon.ico"> + <title><%= webpackConfig.name %></title> + </head> + <body> + <div id="app"></div> + <!-- built files will be auto injected --> + </body> +</html> diff --git a/UI source code/dns_mapping_ui-master/public/sjData/china.js b/UI source code/dns_mapping_ui-master/public/sjData/china.js new file mode 100644 index 0000000..eeec81f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/public/sjData/china.js @@ -0,0 +1,139 @@ +export const ChineseProvinces = [{ + name: '北京', + log_lat: [116.4551, 40.2539, 1], + value: 2, + }, + { + name: '黑龙江', + log_lat: [127.9688, 45.3686, 1], + value: 1 + }, { + name: '内蒙古', + log_lat: [110.3467, 41.4899, 1], + value: 1, + }, { + name: '吉林', + log_lat: [125.8154, 44.2584, 1], + value: 1, + }, { + name: '辽宁', + log_lat: [123.1238, 42.1216, 1], + value: 1, + }, { + name: '河北', + log_lat: [114.4995, 38.1006, 1], + value: 1, + }, { + name: '天津', + log_lat: [117.4219, 39.4189, 1], + value: 1, + }, { + name: '山西', + log_lat: [112.3352, 37.9413, 1], + value: 1, + }, { + name: '陕西', + log_lat: [109.1162, 34.2004, 1], + value: 1, + }, { + name: '甘肃', + log_lat: [103.5901, 36.3043, 1], + value: 1, + }, { + name: '宁夏', + log_lat: [106.3586, 38.1775, 1], + value: 1, + }, { + name: '青海', + log_lat: [101.4038, 36.8207, 1], + value: 1, + }, { + name: '新疆', + log_lat: [87.9236, 43.5883, 1], + value: 1, + }, { + name: '西藏', + log_lat: [91.1661, 29.9667, 1], + value: 1, + }, { + name: '四川', + log_lat: [103.9526, 30.7617, 1], + value: 1, + }, { + name: '重庆', + log_lat: [108.3866, 30.4302, 1], + value: 1, + }, { + name: '山东', + log_lat: [117.1582, 36.8701, 1], + value: 1, + }, { + name: '河南', + log_lat: [113.4668, 34.6234, 1], + value: 1, + }, { + name: '江苏', + log_lat: [118.8062, 31.9208, 1], + value: 1, + }, { + name: '安徽', + log_lat: [117.2879, 32.0581, 1], + value: 1, + }, { + name: '湖北', + log_lat: [114.3896, 30.6628, 1], + value: 1, + }, { + name: '浙江', + log_lat: [119.5313, 29.8773, 1], + value: 1, + }, { + name: '福建', + log_lat: [119.4543, 25.9222, 1], + value: 1, + }, { + name: '江西', + log_lat: [116.0046, 28.6633, 1], + value: 1, + }, { + name: '湖南', + log_lat: [113.0823, 28.2568, 1], + value: 1, + }, { + name: '贵州', + log_lat: [106.6992, 26.7682, 1], + value: 1, + }, { + name: '广东', + log_lat: [113.1244, 23.0005, 1], + value: 1, + }, { + name: '广西', + log_lat: [108.4769, 23.1152, 1], + value: 1, + }, { + name: '云南', + log_lat: [102.9199, 25.4663, 1], + value: 1, + }, { + name: '海南', + log_lat: [110.3893, 19.8516, 1], + value: 1, + }, { + name: '上海', + log_lat: [121.4648, 31.2891, 1], + value: 1, + }, { + name: '台湾', + log_lat: [121.4068, 24.9763, 1], + value: 1, + }, { + name: '澳门', + log_lat: [113.3783, 22.11, 1], + value: 1, + }, { + name: '香港', + log_lat: [114.1545, 22.15, 1], + value: 1, + }, +]
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/public/sjData/china.json b/UI source code/dns_mapping_ui-master/public/sjData/china.json new file mode 100644 index 0000000..9ecfdcb --- /dev/null +++ b/UI source code/dns_mapping_ui-master/public/sjData/china.json @@ -0,0 +1,996 @@ +{ + "type":"FeatureCollection", + "features":[ + { + "type":"Feature", + "id":"xin_jiang", + "properties":{ + "name":"新疆", + "cp":[84.9023,41.748], + "childNum":18}, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [96.416,42.7588],[96.416,42.7148],[95.9766,42.4951],[96.0645,42.3193],[96.2402,42.2314],[95.9766,41.9238], + [95.2734,41.6162],[95.1855,41.792],[94.5703,41.4844],[94.043,41.0889],[93.8672,40.6934],[93.0762,40.6494], + [92.6367,39.6387],[92.373,39.3311],[92.373,39.1113],[92.373,39.0234],[90.1758,38.4961],[90.3516,38.2324], + [90.6152,38.3203],[90.5273,37.8369],[91.0547,37.4414],[91.3184,37.0898],[90.7031,36.7822],[90.791,36.6064], + [91.0547,36.5186],[91.0547,36.0791],[90.8789,36.0352],[90,36.2549],[89.9121,36.0791],[89.7363,36.0791], + [89.209,36.2988],[88.7695,36.3428],[88.5938,36.4746],[87.3633,36.4307],[86.2207,36.167],[86.1328,35.8594], + [85.6055,35.6836],[85.0781,35.7275],[84.1992,35.376],[83.1445,35.4199],[82.8809,35.6836],[82.4414,35.7275], + [82.002,35.332],[81.6504,35.2441],[80.4199,35.4199],[80.2441,35.2881],[80.332,35.1563],[80.2441,35.2002], + [79.8926,34.8047],[79.8047,34.4971],[79.1016,34.4531],[79.0137,34.3213],[78.2227,34.7168],[78.0469,35.2441], + [78.0469,35.5078],[77.4316,35.4639],[76.8164,35.6396],[76.5527,35.8594],[76.2012,35.8154],[75.9375,36.0352], + [76.0254,36.4746],[75.8496,36.6943],[75.498,36.7383],[75.4102,36.958],[75.0586,37.002],[74.8828,36.9141], + [74.7949,37.0459],[74.5313,37.0898],[74.5313,37.2217],[74.8828,37.2217],[75.1465,37.4414],[74.8828,37.5732], + [74.9707,37.749],[74.8828,38.4521],[74.3555,38.6719],[74.1797,38.6719],[74.0918,38.54],[73.8281,38.584], + [73.7402,38.8477],[73.8281,38.9795],[73.4766,39.375],[73.916,39.5068],[73.916,39.6826],[73.8281,39.7705], + [74.0039,40.0342],[74.8828,40.3418],[74.7949,40.5176],[75.2344,40.4297],[75.5859,40.6494],[75.7617,40.2979], + [76.377,40.3857],[76.9043,41.001],[77.6074,41.001],[78.1348,41.2207],[78.1348,41.3965],[80.1563,42.0557], + [80.2441,42.2754],[80.1563,42.627],[80.2441,42.8467],[80.5078,42.8906],[80.4199,43.0664],[80.7715,43.1982], + [80.4199,44.165],[80.4199,44.6045],[79.9805,44.8242],[79.9805,44.9561],[81.7383,45.3955],[82.0898,45.2197], + [82.5293,45.2197],[82.2656,45.6592],[83.0566,47.2412],[83.6719,47.0215],[84.7266,47.0215],[84.9023,46.8896], + [85.5176,47.0654],[85.6934,47.2852],[85.5176,48.1201],[85.7813,48.4277],[86.5723,48.5596],[86.8359,48.8232], + [86.748,48.9551],[86.8359,49.1309],[87.8027,49.1748],[87.8906,48.999],[87.7148,48.9111],[88.0664,48.7354], + [87.9785,48.6035],[88.5059,48.3838],[88.6816,48.1641],[89.1211,47.9883],[89.5605,48.0322],[89.7363,47.8564], + [90.0879,47.8564],[90.3516,47.6807],[90.5273,47.2412],[90.8789,46.9775],[91.0547,46.582],[90.8789,46.3184], + [91.0547,46.0107],[90.7031,45.7471],[90.7031,45.5273],[90.8789,45.2197],[91.582,45.0879],[93.5156,44.9561], + [94.7461,44.3408],[95.3613,44.2969],[95.3613,44.0332],[95.5371,43.9014],[95.8887,43.2422],[96.3281,42.9346], + [96.416,42.7588] + ]] + } + }, + { + "type":"Feature", + "id":"xi_zang", + "properties":{ + "name":"西藏", + "cp":[88.7695,31.6846], + "childNum":7 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [79.0137,34.3213],[79.1016,34.4531],[79.8047,34.4971],[79.8926,34.8047],[80.2441,35.2002],[80.332,35.1563], + [80.2441,35.2881],[80.4199,35.4199],[81.6504,35.2441],[82.002,35.332],[82.4414,35.7275],[82.8809,35.6836], + [83.1445,35.4199],[84.1992,35.376],[85.0781,35.7275],[85.6055,35.6836],[86.1328,35.8594],[86.2207,36.167], + [87.3633,36.4307],[88.5938,36.4746],[88.7695,36.3428],[89.209,36.2988],[89.7363,36.0791],[89.3848,36.0352], + [89.4727,35.9033],[89.7363,35.7715],[89.7363,35.4199],[89.4727,35.376],[89.4727,35.2441],[89.5605,34.8926], + [89.8242,34.8486],[89.7363,34.6729],[89.8242,34.3652],[89.6484,34.0137],[90.0879,33.4863],[90.7031,33.1348], + [91.4063,33.1348],[91.9336,32.8271],[92.1973,32.8271],[92.2852,32.7393],[92.9883,32.7393],[93.5156,32.4756], + [93.7793,32.5635],[94.1309,32.4316],[94.6582,32.6074],[95.1855,32.4316],[95.0098,32.2998],[95.1855,32.3438], + [95.2734,32.2119],[95.3613,32.168],[95.3613,31.9922],[95.4492,31.8164],[95.8008,31.6846],[95.9766,31.8164], + [96.1523,31.5967],[96.2402,31.9482],[96.5039,31.7285],[96.8555,31.6846],[96.7676,31.9922],[97.2949,32.0801], + [97.3828,32.5635],[97.7344,32.5195],[98.1738,32.3438],[98.4375,31.8604],[98.877,31.4209],[98.6133,31.2012], + [98.9648,30.7617],[99.1406,29.2676],[98.9648,29.1357],[98.9648,28.8281],[98.7891,28.8721],[98.7891,29.0039], + [98.7012,28.916],[98.6133,28.5205],[98.7891,28.3447],[98.7012,28.2129],[98.3496,28.125],[98.2617,28.3887], + [98.1738,28.125],[97.5586,28.5205],[97.2949,28.0811],[97.3828,27.9053],[97.0313,27.7295],[96.5039,28.125], + [95.7129,28.2568],[95.3613,28.125],[95.2734,27.9492],[94.2188,27.5537],[93.8672,27.0264],[93.6035,26.9385], + [92.1094,26.8506],[92.0215,27.4658],[91.582,27.5537],[91.582,27.9053],[91.4063,28.0371],[91.0547,27.8613], + [90.7031,28.0811],[89.8242,28.2129],[89.6484,28.1689],[89.1211,27.5977],[89.1211,27.334],[89.0332,27.2021], + [88.7695,27.4219],[88.8574,27.9932],[88.6816,28.125],[88.1543,27.9053],[87.8906,27.9492],[87.7148,27.8174], + [87.0996,27.8174],[86.748,28.125],[86.5723,28.125],[86.4844,27.9053],[86.1328,28.125],[86.0449,27.9053], + [85.6934,28.3447],[85.6055,28.2568],[85.166,28.3447],[85.166,28.6523],[84.9023,28.5645],[84.4629,28.7402], + [84.2871,28.8721],[84.1992,29.2236],[84.1113,29.2676],[83.584,29.1797],[83.2324,29.5752],[82.1777,30.0586], + [82.0898,30.3223],[81.3867,30.3662],[81.2109,30.0146],[81.0352,30.2344],[80.0684,30.5859],[79.7168,30.9375], + [79.0137,31.0693],[78.75,31.333],[78.8379,31.5967],[78.6621,31.8164],[78.75,31.9043],[78.4863,32.124], + [78.3984,32.5195],[78.75,32.6953],[78.9258,32.3438],[79.2773,32.5635],[79.1016,33.1787],[78.6621,33.6621], + [78.6621,34.1016],[78.9258,34.1455],[79.0137,34.3213] + ] + ] + } + }, + { + "type":"Feature", + "id":"nei_meng_gu", + "properties":{ + "name":"内蒙古", + "cp":[117.5977,44.3408], + "childNum":12 + }, + "geometry": { + "type":"Polygon", + "coordinates":[ + [ + [97.207,42.8027],[99.4922,42.583],[100.8105,42.6709],[101.7773,42.4951],[102.041,42.2314],[102.7441,42.1436], + [103.3594,41.8799],[103.8867,41.792],[104.502,41.8799],[104.502,41.6602],[105.0293,41.5723],[105.7324,41.9238], + [107.4023,42.4512],[109.4238,42.4512],[110.3906,42.7588],[111.0059,43.3301],[111.9727,43.6816],[111.9727,43.8135], + [111.4453,44.3848],[111.7969,45],[111.9727,45.0879],[113.6426,44.7363],[114.1699,44.9561],[114.5215,45.3955], + [115.6641,45.4395],[116.1914,45.7031],[116.2793,45.9668],[116.543,46.2744],[117.334,46.3623],[117.4219,46.582], + [117.7734,46.5381],[118.3008,46.7578],[118.7402,46.7139],[118.916,46.7578],[119.0918,46.6699],[119.707,46.626], + [119.9707,46.7139],[119.707,47.1973],[118.4766,47.9883],[117.8613,48.0322],[117.334,47.6807],[116.8066,47.9004], + [116.1914,47.8564],[115.9277,47.6807],[115.5762,47.9004],[115.4883,48.1641],[115.8398,48.252],[115.8398,48.5596], + [116.7188,49.834],[117.7734,49.5264],[118.5645,49.9219],[119.2676,50.0977],[119.3555,50.3174],[119.1797,50.3613], + [119.5313,50.7568],[119.5313,50.8887],[119.707,51.0645],[120.1465,51.6797],[120.6738,51.9434],[120.7617,52.1191], + [120.7617,52.251],[120.5859,52.3389],[120.6738,52.5146],[120.4102,52.6465],[120.0586,52.6025],[120.0586,52.7344], + [120.8496,53.2617],[121.4648,53.3496],[121.8164,53.042],[121.2012,52.5586],[121.6406,52.4268],[121.7285,52.2949], + [121.9922,52.2949],[122.168,52.5146],[122.6953,52.251],[122.6074,52.0752],[122.959,51.3281],[123.3105,51.2402], + [123.6621,51.3721],[124.3652,51.2842],[124.541,51.3721],[124.8926,51.3721],[125.0684,51.6357],[125.332,51.6357], + [126.0352,51.0205],[125.7715,50.7568],[125.7715,50.5371],[125.332,50.1416],[125.1563,49.834],[125.2441,49.1748], + [124.8047,49.1309],[124.4531,48.1201],[124.2773,48.5156],[122.4316,47.373],[123.0469,46.7139],[123.3984,46.8896], + [123.3984,46.9775],[123.4863,46.9775],[123.5742,46.8457],[123.5742,46.8896],[123.5742,46.6699],[123.0469,46.582], + [123.2227,46.2305],[122.7832,46.0107],[122.6953,45.7031],[122.4316,45.8789],[122.2559,45.791],[121.8164,46.0107], + [121.7285,45.7471],[121.9043,45.7031],[122.2559,45.2637],[122.0801,44.8682],[122.3438,44.2529],[123.1348,44.4727], + [123.4863,43.7256],[123.3105,43.5059],[123.6621,43.374],[123.5742,43.0225],[123.3105,42.9785],[123.1348,42.8027], + [122.7832,42.7148],[122.3438,42.8467],[122.3438,42.6709],[121.9922,42.7148],[121.7285,42.4512],[121.4648,42.4951], + [120.498,42.0996],[120.1465,41.7041],[119.8828,42.1875],[119.5313,42.3633],[119.3555,42.2754],[119.2676,41.7041], + [119.4434,41.6162],[119.2676,41.3086],[118.3887,41.3086],[118.125,41.748],[118.3008,41.792],[118.3008,42.0996], + [118.125,42.0557],[117.9492,42.2314],[118.0371,42.4072],[117.7734,42.627],[117.5098,42.583],[117.334,42.4512], + [116.8945,42.4072],[116.8066,42.0117],[116.2793,42.0117],[116.0156,41.792],[115.9277,41.9238],[115.2246,41.5723], + [114.9609,41.6162],[114.873,42.0996],[114.5215,42.1436],[114.1699,41.792],[114.2578,41.5723],[113.9063,41.4404], + [113.9941,41.2207],[113.9063,41.1328],[114.082,40.7373],[114.082,40.5176],[113.8184,40.5176],[113.5547,40.3418], + [113.2031,40.3857],[112.7637,40.166],[112.3242,40.2539],[111.9727,39.5947],[111.4453,39.6387],[111.3574,39.4189], + [111.0938,39.375],[111.0938,39.5947],[110.6543,39.2871],[110.127,39.4629],[110.2148,39.2871],[109.8633,39.2432], + [109.9512,39.1553],[108.9844,38.3203],[109.0723,38.0127],[108.8965,37.9688],[108.8086,38.0127],[108.7207,37.7051], + [108.1934,37.6172],[107.666,37.8809],[107.3145,38.1006],[106.7871,38.1885],[106.5234,38.3203],[106.9629,38.9795], + [106.7871,39.375],[106.3477,39.2871],[105.9082,38.7158],[105.8203,37.793],[104.3262,37.4414],[103.4473,37.8369], + [103.3594,38.0127],[103.5352,38.1445],[103.4473,38.3643],[104.2383,38.9795],[104.0625,39.4189],[103.3594,39.3311], + [103.0078,39.1113],[102.4805,39.2432],[101.8652,39.1113],[102.041,38.8916],[101.7773,38.6719],[101.3379,38.7598], + [101.25,39.0234],[100.9863,38.9355],[100.8105,39.4189],[100.5469,39.4189],[100.0195,39.7705],[99.4922,39.8584], + [100.1074,40.2539],[100.1953,40.6494],[99.9316,41.001],[99.2285,40.8691],[99.0527,40.6934],[98.9648,40.7813], + [98.7891,40.6055],[98.5254,40.7373],[98.6133,40.6494],[98.3496,40.5615],[98.3496,40.9131],[97.4707,41.4844], + [97.8223,41.6162],[97.8223,41.748],[97.207,42.8027] + ] + ] + } + }, + { + "type":"Feature", + "id":"qing_hai", + "properties":{ + "name":"青海", + "cp":[96.2402,35.4199], + "childNum":8 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [89.7363,36.0791],[89.9121,36.0791],[90,36.2549],[90.8789,36.0352],[91.0547,36.0791],[91.0547,36.5186], + [90.791,36.6064],[90.7031,36.7822],[91.3184,37.0898],[91.0547,37.4414],[90.5273,37.8369],[90.6152,38.3203], + [90.3516,38.2324],[90.1758,38.4961],[92.373,39.0234],[92.373,39.1113],[93.1641,39.1992],[93.1641,38.9795], + [93.6914,38.9355],[93.8672,38.7158],[94.3066,38.7598],[94.5703,38.3643],[95.0098,38.4082],[95.4492,38.2764], + [95.7129,38.3643],[96.2402,38.1006],[96.416,38.2324],[96.6797,38.1885],[96.6797,38.4521],[97.1191,38.584], + [97.0313,39.1992],[98.1738,38.8037],[98.3496,39.0234],[98.6133,38.9355],[98.7891,39.0674],[99.1406,38.9355], + [99.8438,38.3643],[100.1953,38.2764],[100.0195,38.4521],[100.1074,38.4961],[100.459,38.2764],[100.7227,38.2324], + [101.1621,37.8369],[101.5137,37.8809],[101.7773,37.6172],[101.9531,37.7051],[102.1289,37.4414],[102.5684,37.1777], + [102.4805,36.958],[102.6563,36.8262],[102.5684,36.7383],[102.832,36.3428],[103.0078,36.2549],[102.9199,36.0791], + [102.9199,35.9033],[102.6563,35.7715],[102.832,35.5957],[102.4805,35.5957],[102.3047,35.4199],[102.3926,35.2002], + [101.9531,34.8486],[101.9531,34.6289],[102.2168,34.4092],[102.1289,34.2773],[101.6895,34.1016],[100.9863,34.3652], + [100.8105,34.2773],[101.25,33.6621],[101.5137,33.7061],[101.6016,33.5303],[101.7773,33.5303],[101.6895,33.3105], + [101.7773,33.2227],[101.6016,33.1348],[101.1621,33.2227],[101.25,32.6953],[100.7227,32.6514],[100.7227,32.5195], + [100.3711,32.7393],[100.1074,32.6514],[100.1074,32.8711],[99.8438,33.0029],[99.7559,32.7393],[99.2285,32.915], + [99.2285,33.0469],[98.877,33.1787],[98.4375,34.0576],[97.8223,34.1895],[97.6465,34.1016],[97.7344,33.9258], + [97.3828,33.8818],[97.4707,33.5742],[97.7344,33.3984],[97.3828,32.8711],[97.4707,32.6953],[97.7344,32.5195], + [97.3828,32.5635],[97.2949,32.0801],[96.7676,31.9922],[96.8555,31.6846],[96.5039,31.7285],[96.2402,31.9482], + [96.1523,31.5967],[95.9766,31.8164],[95.8008,31.6846],[95.4492,31.8164],[95.3613,31.9922],[95.3613,32.168], + [95.2734,32.2119],[95.1855,32.3438],[95.0098,32.2998],[95.1855,32.4316],[94.6582,32.6074],[94.1309,32.4316], + [93.7793,32.5635],[93.5156,32.4756],[92.9883,32.7393],[92.2852,32.7393],[92.1973,32.8271],[91.9336,32.8271], + [91.4063,33.1348],[90.7031,33.1348],[90.0879,33.4863],[89.6484,34.0137],[89.8242,34.3652],[89.7363,34.6729], + [89.8242,34.8486],[89.5605,34.8926],[89.4727,35.2441],[89.4727,35.376],[89.7363,35.4199],[89.7363,35.7715], + [89.4727,35.9033],[89.3848,36.0352],[89.7363,36.0791] + ] + ] + } + }, + { + "type":"Feature", + "id":"si_chuan", + "properties":{ + "name":"四川", + "cp":[102.9199,30.1904], + "childNum":21 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [101.7773,33.5303],[101.8652,33.5742],[101.9531,33.4424],[101.8652,33.0908],[102.4805,33.4424],[102.2168,33.9258], + [102.9199,34.3213],[103.0957,34.1895],[103.1836,33.7939],[104.1504,33.6182],[104.2383,33.3984],[104.4141,33.3105], + [104.3262,33.2227],[104.4141,33.0469],[104.3262,32.8711],[104.4141,32.7393],[105.2051,32.6074],[105.3809,32.7393], + [105.3809,32.8711],[105.4688,32.915],[105.5566,32.7393],[106.084,32.8711],[106.084,32.7393],[106.3477,32.6514], + [107.0508,32.6953],[107.1387,32.4756],[107.2266,32.4316],[107.4023,32.5195],[108.0176,32.168],[108.2813,32.2559], + [108.5449,32.2119],[108.3691,32.168],[108.2813,31.9043],[108.5449,31.6846],[108.1934,31.5088],[107.9297,30.8496], + [107.4902,30.8496],[107.4023,30.7617],[107.4902,30.6299],[107.0508,30.0146],[106.7871,30.0146],[106.6113,30.3223], + [106.2598,30.1904],[105.8203,30.4541],[105.6445,30.2783],[105.5566,30.1025],[105.7324,29.8828],[105.293,29.5313], + [105.4688,29.3115],[105.7324,29.2676],[105.8203,28.96],[106.2598,28.8721],[106.3477,28.5205],[105.9961,28.7402], + [105.6445,28.4326],[105.9082,28.125],[106.1719,28.125],[106.3477,27.8174],[105.6445,27.6416],[105.5566,27.7734], + [105.293,27.7295],[105.2051,27.9932],[105.0293,28.0811],[104.8535,27.9053],[104.4141,27.9492],[104.3262,28.0371], + [104.4141,28.125],[104.4141,28.2568],[104.2383,28.4326],[104.4141,28.6084],[103.8867,28.6523],[103.7988,28.3008], + [103.4473,28.125],[103.4473,27.7734],[102.9199,27.29],[103.0078,26.3672],[102.6563,26.1914],[102.5684,26.3672], + [102.1289,26.1035],[101.8652,26.0596],[101.6016,26.2354],[101.6895,26.3672],[101.4258,26.5869],[101.4258,26.8066], + [101.4258,26.7188],[101.1621,27.0264],[101.1621,27.1582],[100.7227,27.8613],[100.3711,27.8174],[100.2832,27.7295], + [100.0195,28.125],[100.1953,28.3447],[99.668,28.8281],[99.4043,28.5205],[99.4043,28.1689],[99.2285,28.3008], + [99.1406,29.2676],[98.9648,30.7617],[98.6133,31.2012],[98.877,31.4209],[98.4375,31.8604],[98.1738,32.3438], + [97.7344,32.5195],[97.4707,32.6953],[97.3828,32.8711],[97.7344,33.3984],[97.4707,33.5742],[97.3828,33.8818], + [97.7344,33.9258],[97.6465,34.1016],[97.8223,34.1895],[98.4375,34.0576],[98.877,33.1787],[99.2285,33.0469], + [99.2285,32.915],[99.7559,32.7393],[99.8438,33.0029],[100.1074,32.8711],[100.1074,32.6514],[100.3711,32.7393], + [100.7227,32.5195],[100.7227,32.6514],[101.25,32.6953],[101.1621,33.2227],[101.6016,33.1348],[101.7773,33.2227], + [101.6895,33.3105],[101.7773,33.5303] + ] + ] + } + }, + { + "type":"Feature", + "id":"hei_long_jiang", + "properties":{ + "name":"黑龙江", + "cp":[128.1445,48.5156], + "childNum":13 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [121.4648,53.3496],[123.6621,53.5693],[124.8926,53.0859],[125.0684,53.2178],[125.5957,53.0859],[125.6836,52.9102], + [126.123,52.7783],[126.0352,52.6025],[126.2109,52.5146],[126.3867,52.2949],[126.3867,52.207],[126.5625,52.1631], + [126.4746,51.9434],[126.9141,51.3721],[126.8262,51.2842],[127.002,51.3281],[126.9141,51.1084],[127.2656,50.7568], + [127.3535,50.2734],[127.6172,50.2295],[127.5293,49.8779],[127.793,49.6143],[128.7598,49.5703],[129.1113,49.3506], + [129.4629,49.4385],[130.2539,48.8672],[130.6934,48.8672],[130.5176,48.6475],[130.8691,48.2959],[130.6934,48.1201], + [131.0449,47.6807],[132.5391,47.7246],[132.627,47.9443],[133.0664,48.1201],[133.5059,48.1201],[134.209,48.3838], + [135.0879,48.4277],[134.7363,48.252],[134.5605,47.9883],[134.7363,47.6807],[134.5605,47.4609],[134.3848,47.4609], + [134.209,47.2852],[134.209,47.1533],[133.8574,46.5381],[133.9453,46.2744],[133.5059,45.835],[133.418,45.5713], + [133.2422,45.5273],[133.0664,45.1318],[132.8906,45.0439],[131.9238,45.3516],[131.5723,45.0439],[131.0449,44.8682], + [131.3086,44.0771],[131.2207,43.7256],[131.3086,43.4619],[130.8691,43.418],[130.5176,43.6377],[130.3418,43.9893], + [129.9902,43.8574],[129.9023,44.0332],[129.8145,43.9014],[129.2871,43.8135],[129.1992,43.5938],[128.8477,43.5498], + [128.4961,44.165],[128.4082,44.4727],[128.0566,44.3408],[128.0566,44.1211],[127.7051,44.1211],[127.5293,44.6045], + [127.0898,44.6045],[127.002,44.7803],[127.0898,45],[126.9141,45.1318],[126.5625,45.2637],[126.0352,45.1758], + [125.7715,45.3076],[125.6836,45.5273],[125.0684,45.3955],[124.8926,45.5273],[124.3652,45.4395],[124.0137,45.7471], + [123.9258,46.2305],[123.2227,46.2305],[123.0469,46.582],[123.5742,46.6699],[123.5742,46.8896],[123.5742,46.8457], + [123.4863,46.9775],[123.3984,46.9775],[123.3984,46.8896],[123.0469,46.7139],[122.4316,47.373],[124.2773,48.5156], + [124.4531,48.1201],[124.8047,49.1309],[125.2441,49.1748],[125.1563,49.834],[125.332,50.1416],[125.7715,50.5371], + [125.7715,50.7568],[126.0352,51.0205],[125.332,51.6357],[125.0684,51.6357],[124.8926,51.3721],[124.541,51.3721], + [124.3652,51.2842],[123.6621,51.3721],[123.3105,51.2402],[122.959,51.3281],[122.6074,52.0752],[122.6953,52.251], + [122.168,52.5146],[121.9922,52.2949],[121.7285,52.2949],[121.6406,52.4268],[121.2012,52.5586],[121.8164,53.042], + [121.4648,53.3496] + ] + ] + } + }, + { + "type":"Feature", + "id":"gan_su", + "properties":{ + "name":"甘肃", + "cp":[95.7129,40.166], + "childNum":14 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [96.416,42.7148],[97.207,42.8027],[97.8223,41.748],[97.8223,41.6162],[97.4707,41.4844],[98.3496,40.9131], + [98.3496,40.5615],[98.6133,40.6494],[98.5254,40.7373],[98.7891,40.6055],[98.9648,40.7813],[99.0527,40.6934], + [99.2285,40.8691],[99.9316,41.001],[100.1953,40.6494],[100.1074,40.2539],[99.4922,39.8584],[100.0195,39.7705], + [100.5469,39.4189],[100.8105,39.4189],[100.9863,38.9355],[101.25,39.0234],[101.3379,38.7598],[101.7773,38.6719], + [102.041,38.8916],[101.8652,39.1113],[102.4805,39.2432],[103.0078,39.1113],[103.3594,39.3311],[104.0625,39.4189], + [104.2383,38.9795],[103.4473,38.3643],[103.5352,38.1445],[103.3594,38.0127],[103.4473,37.8369],[104.3262,37.4414], + [104.5898,37.4414],[104.5898,37.2217],[104.8535,37.2217],[105.293,36.8262],[105.2051,36.6943],[105.4688,36.123], + [105.293,35.9912],[105.3809,35.7715],[105.7324,35.7275],[105.8203,35.5518],[105.9961,35.4639],[105.9082,35.4199], + [105.9961,35.4199],[106.084,35.376],[106.2598,35.4199],[106.3477,35.2441],[106.5234,35.332],[106.4355,35.6836], + [106.6992,35.6836],[106.9629,35.8154],[106.875,36.123],[106.5234,36.2549],[106.5234,36.4746],[106.4355,36.5625], + [106.6113,36.7822],[106.6113,37.0898],[107.3145,37.0898],[107.3145,36.9141],[108.7207,36.3428],[108.6328,35.9912], + [108.5449,35.8594],[108.6328,35.5518],[108.5449,35.2881],[107.7539,35.2881],[107.7539,35.1123],[107.8418,35.0244], + [107.666,34.9365],[107.2266,34.8926],[106.9629,35.0684],[106.6113,35.0684],[106.5234,34.7607],[106.3477,34.585], + [106.6992,34.3213],[106.5234,34.2773],[106.6113,34.1455],[106.4355,33.9258],[106.5234,33.5303],[105.9961,33.6182], + [105.7324,33.3984],[105.9961,33.1787],[105.9082,33.0029],[105.4688,32.915],[105.3809,32.8711],[105.3809,32.7393], + [105.2051,32.6074],[104.4141,32.7393],[104.3262,32.8711],[104.4141,33.0469],[104.3262,33.2227],[104.4141,33.3105], + [104.2383,33.3984],[104.1504,33.6182],[103.1836,33.7939],[103.0957,34.1895],[102.9199,34.3213],[102.2168,33.9258], + [102.4805,33.4424],[101.8652,33.0908],[101.9531,33.4424],[101.8652,33.5742],[101.7773,33.5303],[101.6016,33.5303], + [101.5137,33.7061],[101.25,33.6621],[100.8105,34.2773],[100.9863,34.3652],[101.6895,34.1016],[102.1289,34.2773], + [102.2168,34.4092],[101.9531,34.6289],[101.9531,34.8486],[102.3926,35.2002],[102.3047,35.4199],[102.4805,35.5957], + [102.832,35.5957],[102.6563,35.7715],[102.9199,35.9033],[102.9199,36.0791],[103.0078,36.2549],[102.832,36.3428], + [102.5684,36.7383],[102.6563,36.8262],[102.4805,36.958],[102.5684,37.1777],[102.1289,37.4414],[101.9531,37.7051], + [101.7773,37.6172],[101.5137,37.8809],[101.1621,37.8369],[100.7227,38.2324],[100.459,38.2764],[100.1074,38.4961], + [100.0195,38.4521],[100.1953,38.2764],[99.8438,38.3643],[99.1406,38.9355],[98.7891,39.0674],[98.6133,38.9355], + [98.3496,39.0234],[98.1738,38.8037],[97.0313,39.1992],[97.1191,38.584],[96.6797,38.4521],[96.6797,38.1885], + [96.416,38.2324],[96.2402,38.1006],[95.7129,38.3643],[95.4492,38.2764],[95.0098,38.4082],[94.5703,38.3643], + [94.3066,38.7598],[93.8672,38.7158],[93.6914,38.9355],[93.1641,38.9795],[93.1641,39.1992],[92.373,39.1113], + [92.373,39.3311],[92.6367,39.6387],[93.0762,40.6494],[93.8672,40.6934],[94.043,41.0889],[94.5703,41.4844], + [95.1855,41.792],[95.2734,41.6162],[95.9766,41.9238],[96.2402,42.2314],[96.0645,42.3193],[95.9766,42.4951], + [96.416,42.7148]] + ] + } + }, + { + "type":"Feature", + "id":"yun_nan", + "properties":{ + "name":"云南", + "cp":[101.8652,25.1807], + "childNum":16 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [98.1738,28.125],[98.2617,28.3887],[98.3496,28.125],[98.7012,28.2129],[98.7891,28.3447],[98.6133,28.5205], + [98.7012,28.916],[98.7891,29.0039],[98.7891,28.8721],[98.9648,28.8281],[98.9648,29.1357],[99.1406,29.2676], + [99.2285,28.3008],[99.4043,28.1689],[99.4043,28.5205],[99.668,28.8281],[100.1953,28.3447],[100.0195,28.125], + [100.2832,27.7295],[100.3711,27.8174],[100.7227,27.8613],[101.1621,27.1582],[101.1621,27.0264],[101.4258,26.7188], + [101.4258,26.8066],[101.4258,26.5869],[101.6895,26.3672],[101.6016,26.2354],[101.8652,26.0596],[102.1289,26.1035], + [102.5684,26.3672],[102.6563,26.1914],[103.0078,26.3672],[102.9199,27.29],[103.4473,27.7734],[103.4473,28.125], + [103.7988,28.3008],[103.8867,28.6523],[104.4141,28.6084],[104.2383,28.4326],[104.4141,28.2568],[104.4141,28.125], + [104.3262,28.0371],[104.4141,27.9492],[104.8535,27.9053],[105.0293,28.0811],[105.2051,27.9932],[105.293,27.7295], + [105.2051,27.3779],[104.5898,27.334],[104.4141,27.4658],[104.1504,27.2461],[103.8867,27.4219],[103.623,27.0264], + [103.7109,26.9824],[103.7109,26.7627],[103.8867,26.543],[104.4141,26.6748],[104.6777,26.4111],[104.3262,25.708], + [104.8535,25.2246],[104.5898,25.0488],[104.6777,24.9609],[104.502,24.7412],[104.6777,24.3457],[104.7656,24.4775], + [105.0293,24.4336],[105.2051,24.082],[105.4688,24.0381],[105.5566,24.126],[105.9961,24.126],[106.1719,23.8184], + [106.1719,23.5547],[105.6445,23.4229],[105.5566,23.2031],[105.293,23.3789],[104.8535,23.1592],[104.7656,22.8516], + [104.3262,22.6758],[104.1504,22.8076],[103.9746,22.5439],[103.623,22.7637],[103.5352,22.5879],[103.3594,22.8076], + [103.0957,22.4561],[102.4805,22.7637],[102.3047,22.4121],[101.8652,22.3682],[101.7773,22.5],[101.6016,22.1924], + [101.8652,21.6211],[101.7773,21.1377],[101.6016,21.2256],[101.25,21.1816],[101.1621,21.7529],[100.6348,21.4453], + [100.1074,21.4893],[99.9316,22.0605],[99.2285,22.1484],[99.4043,22.5879],[99.3164,22.7197],[99.4922,23.0713], + [98.877,23.2031],[98.7012,23.9502],[98.877,24.126],[98.1738,24.082],[97.7344,23.8623],[97.5586,23.9063], + [97.7344,24.126],[97.6465,24.4336],[97.5586,24.4336],[97.5586,24.7412],[97.7344,24.8291],[97.8223,25.2686], + [98.1738,25.4004],[98.1738,25.6201],[98.3496,25.5762],[98.5254,25.8398],[98.7012,25.8838],[98.6133,26.0596], + [98.7012,26.1475],[98.7891,26.5869],[98.7012,27.5098],[98.5254,27.6416],[98.3496,27.5098],[98.1738,28.125] + ] + ] + } + }, + { + "type":"Feature", + "id":"guang_xi", + "properties":{ + "name":"广西", + "cp":[108.2813,23.6426], + "childNum":14 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [104.502,24.7412],[104.6777,24.6094],[105.2051,24.9609],[105.9961,24.6533],[106.1719,24.7852],[106.1719,24.9609], + [106.875,25.1807],[107.0508,25.2686],[106.9629,25.4883],[107.2266,25.6201],[107.4902,25.2246],[107.7539,25.2246], + [107.8418,25.1367],[108.1055,25.2246],[108.1934,25.4443],[108.3691,25.5322],[108.6328,25.3125],[108.6328,25.5762], + [109.0723,25.5322],[108.9844,25.752],[109.3359,25.708],[109.5117,26.0156],[109.7754,25.8838],[109.9512,26.1914], + [110.2148,25.9717],[110.5664,26.3232],[111.1816,26.3232],[111.2695,26.2354],[111.2695,25.8838],[111.4453,25.8398], + [111.0059,25.0049],[111.0938,24.9609],[111.3574,25.1367],[111.5332,24.6533],[111.709,24.7852],[112.0605,24.7412], + [111.8848,24.6533],[112.0605,24.3457],[111.8848,24.2139],[111.8848,23.9941],[111.7969,23.8184],[111.6211,23.8184], + [111.6211,23.6865],[111.3574,23.4668],[111.4453,23.0273],[111.2695,22.8076],[110.7422,22.5439],[110.7422,22.2803], + [110.6543,22.1484],[110.3027,22.1484],[110.3027,21.8848],[109.9512,21.8408],[109.8633,21.665],[109.7754,21.6211], + [109.7754,21.4014],[109.5996,21.4453],[109.1602,21.3574],[109.248,20.874],[109.0723,20.9619],[109.0723,21.5332], + [108.7207,21.5332],[108.6328,21.665],[108.2813,21.4893],[107.8418,21.6211],[107.4023,21.6211],[107.0508,21.7969], + [107.0508,21.9287],[106.6992,22.0166],[106.6113,22.4121],[106.7871,22.7637],[106.6992,22.8955],[105.9082,22.9395], + [105.5566,23.0713],[105.5566,23.2031],[105.6445,23.4229],[106.1719,23.5547],[106.1719,23.8184],[105.9961,24.126], + [105.5566,24.126],[105.4688,24.0381],[105.2051,24.082],[105.0293,24.4336],[104.7656,24.4775],[104.6777,24.3457], + [104.502,24.7412] + ] + ] + } + }, + { + "type":"Feature", + "id":"hu_nan", + "properties":{ + "name":"湖南", + "cp":[111.5332,27.3779], + "childNum":14 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [109.248,28.4766],[109.248,29.1357],[109.5117,29.6191],[109.6875,29.6191],[109.7754,29.751],[110.4785,29.6631], + [110.6543,29.751],[110.4785,30.0146],[110.8301,30.1465],[111.7969,29.9268],[112.2363,29.5313],[112.5,29.6191], + [112.6758,29.5752],[112.9395,29.7949],[113.0273,29.751],[112.9395,29.4873],[113.0273,29.4434],[113.5547,29.8389], + [113.5547,29.707],[113.7305,29.5752],[113.6426,29.3115],[113.7305,29.0918],[113.9063,29.0479],[114.1699,28.8281], + [114.082,28.5645],[114.2578,28.3447],[113.7305,27.9492],[113.6426,27.5977],[113.6426,27.3779],[113.8184,27.29], + [113.7305,27.1143],[113.9063,26.9385],[113.9063,26.6309],[114.082,26.5869],[113.9941,26.1914],[114.2578,26.1475], + [113.9941,26.0596],[113.9063,25.4443],[113.6426,25.3125],[113.2031,25.5322],[112.8516,25.3564],[113.0273,25.2246], + [113.0273,24.9609],[112.8516,24.917],[112.5879,25.1367],[112.2363,25.1807],[112.1484,24.873],[112.0605,24.7412], + [111.709,24.7852],[111.5332,24.6533],[111.3574,25.1367],[111.0938,24.9609],[111.0059,25.0049],[111.4453,25.8398], + [111.2695,25.8838],[111.2695,26.2354],[111.1816,26.3232],[110.5664,26.3232],[110.2148,25.9717],[109.9512,26.1914], + [109.7754,25.8838],[109.5117,26.0156],[109.4238,26.2793],[109.248,26.3232],[109.4238,26.5869],[109.3359,26.7188], + [109.5117,26.8066],[109.5117,27.0264],[109.3359,27.1582],[108.8965,27.0264],[108.8086,27.1143],[109.4238,27.5977], + [109.3359,27.9053],[109.3359,28.2568],[109.248,28.4766] + ] + ] + } + }, + { + "type":"Feature","id":"shan_xi_1", + "properties":{ + "name":"陕西", + "cp":[109.5996,35.6396], + "childNum":10 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [105.4688,32.915],[105.9082,33.0029],[105.9961,33.1787],[105.7324,33.3984],[105.9961,33.6182],[106.5234,33.5303], + [106.4355,33.9258],[106.6113,34.1455],[106.5234,34.2773],[106.6992,34.3213],[106.3477,34.585],[106.5234,34.7607], + [106.6113,35.0684],[106.9629,35.0684],[107.2266,34.8926],[107.666,34.9365],[107.8418,35.0244],[107.7539,35.1123], + [107.7539,35.2881],[108.5449,35.2881],[108.6328,35.5518],[108.5449,35.8594],[108.6328,35.9912],[108.7207,36.3428], + [107.3145,36.9141],[107.3145,37.0898],[107.3145,37.6172],[107.666,37.8809],[108.1934,37.6172],[108.7207,37.7051], + [108.8086,38.0127],[108.8965,37.9688],[109.0723,38.0127],[108.9844,38.3203],[109.9512,39.1553],[109.8633,39.2432], + [110.2148,39.2871],[110.127,39.4629],[110.6543,39.2871],[111.0938,39.5947],[111.0938,39.375],[111.1816,39.2432], + [110.918,38.7158],[110.8301,38.4961],[110.4785,38.1885],[110.4785,37.9688],[110.8301,37.6611],[110.3906,37.002], + [110.4785,36.123],[110.5664,35.6396],[110.2148,34.8926],[110.2148,34.6729],[110.3906,34.585],[110.4785,34.2334], + [110.6543,34.1455],[110.6543,33.8379],[111.0059,33.5303],[111.0059,33.2666],[110.7422,33.1348],[110.5664,33.2666], + [110.3027,33.1787],[109.5996,33.2666],[109.4238,33.1348],[109.7754,33.0469],[109.7754,32.915],[110.127,32.7393], + [110.127,32.6074],[109.6875,32.6074],[109.5117,32.4316],[109.5996,31.7285],[109.248,31.7285],[109.0723,31.9482], + [108.5449,32.2119],[108.2813,32.2559],[108.0176,32.168],[107.4023,32.5195],[107.2266,32.4316],[107.1387,32.4756], + [107.0508,32.6953],[106.3477,32.6514],[106.084,32.7393],[106.084,32.8711],[105.5566,32.7393],[105.4688,32.915] + ] + ] + } + }, + { + "type":"Feature", + "id":"guang_dong", + "properties":{ + "name":"广东", + "cp":[113.4668,22.8076], + "childNum":21 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [109.7754,21.4014],[109.7754,21.6211],[109.8633,21.665],[109.9512,21.8408],[110.3027,21.8848],[110.3027,22.1484], + [110.6543,22.1484],[110.7422,22.2803],[110.7422,22.5439],[111.2695,22.8076],[111.4453,23.0273],[111.3574,23.4668], + [111.6211,23.6865],[111.6211,23.8184],[111.7969,23.8184],[111.8848,23.9941],[111.8848,24.2139],[112.0605,24.3457], + [111.8848,24.6533],[112.0605,24.7412],[112.1484,24.873],[112.2363,25.1807],[112.5879,25.1367],[112.8516,24.917], + [113.0273,24.9609],[113.0273,25.2246],[112.8516,25.3564],[113.2031,25.5322],[113.6426,25.3125],[113.9063,25.4443], + [113.9941,25.2686],[114.6094,25.4004],[114.7852,25.2686],[114.6973,25.1367],[114.4336,24.9609],[114.1699,24.6973], + [114.4336,24.5215],[115.4004,24.7852],[115.8398,24.5654],[115.752,24.7852],[115.9277,24.917],[116.2793,24.7852], + [116.3672,24.873],[116.543,24.6094],[116.7188,24.6533],[116.9824,24.1699],[116.9824,23.9063],[117.1582,23.5547], + [117.334,23.2471],[116.8945,23.3789],[116.6309,23.1152],[116.543,22.8516],[115.9277,22.7197],[115.6641,22.7637], + [115.5762,22.6318],[115.0488,22.6758],[114.6094,22.3682],[114.3457,22.5439],[113.9941,22.5],[113.8184,22.1924], + [114.3457,22.1484],[114.4336,22.0166],[114.082,21.9287],[113.9941,21.7969],[113.5547,22.0166],[113.1152,21.8408], + [112.9395,21.5771],[112.4121,21.4453],[112.2363,21.5332],[111.5332,21.4893],[111.2695,21.3574],[110.7422,21.3574], + [110.6543,21.2256],[110.7422,20.918],[110.4785,20.874],[110.6543,20.2588],[110.5664,20.2588],[110.3906,20.127], + [110.0391,20.127],[109.8633,20.127],[109.8633,20.3027],[109.5996,20.918],[109.7754,21.4014],[109.7754,21.4014] + ], + [ + [113.5986,22.1649],[113.6096,22.1265],[113.5547,22.11],[113.5437,22.2034],[113.5767,22.2034],[113.5986,22.1649] + ] + ] + } + }, + { + "type":"Feature","id":"ji_lin", + "properties":{ + "name":"吉林", + "cp":[126.4746,43.5938], + "childNum":9 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [123.2227,46.2305],[123.9258,46.2305],[124.0137,45.7471],[124.3652,45.4395],[124.8926,45.5273],[125.0684,45.3955], + [125.6836,45.5273],[125.7715,45.3076],[126.0352,45.1758],[126.5625,45.2637],[126.9141,45.1318],[127.0898,45], + [127.002,44.7803],[127.0898,44.6045],[127.5293,44.6045],[127.7051,44.1211],[128.0566,44.1211],[128.0566,44.3408], + [128.4082,44.4727],[128.4961,44.165],[128.8477,43.5498],[129.1992,43.5938],[129.2871,43.8135],[129.8145,43.9014], + [129.9023,44.0332],[129.9902,43.8574],[130.3418,43.9893],[130.5176,43.6377],[130.8691,43.418],[131.3086,43.4619], + [131.3086,43.3301],[131.1328,42.9346],[130.4297,42.7148],[130.6055,42.6709],[130.6055,42.4512],[130.2539,42.7588], + [130.2539,42.8906],[130.166,42.9785],[129.9023,43.0225],[129.7266,42.4951],[129.375,42.4512],[128.9355,42.0117], + [128.0566,42.0117],[128.3203,41.5723],[128.1445,41.3525],[127.0898,41.5283],[127.1777,41.5723],[126.9141,41.792], + [126.6504,41.6602],[126.4746,41.3965],[126.123,40.957],[125.6836,40.8691],[125.5957,40.9131],[125.7715,41.2207], + [125.332,41.6602],[125.332,41.9678],[125.4199,42.0996],[125.332,42.1436],[124.8926,42.8027],[124.8926,43.0664], + [124.7168,43.0664],[124.4531,42.8467],[124.2773,43.2422],[123.8379,43.4619],[123.6621,43.374],[123.3105,43.5059], + [123.4863,43.7256],[123.1348,44.4727],[122.3438,44.2529],[122.0801,44.8682],[122.2559,45.2637],[121.9043,45.7031], + [121.7285,45.7471],[121.8164,46.0107],[122.2559,45.791],[122.4316,45.8789],[122.6953,45.7031],[122.7832,46.0107], + [123.2227,46.2305] + ] + ] + } + }, + { + "type":"Feature", + "id":"he_bei", + "properties":{ + "name":"河北", + "cp":[115.4004,37.9688], + "childNum":11 + }, + "geometry":{ + "type":"MultiPolygon", + "coordinates":[ + [ + [ + [114.5215,39.5068],[114.3457,39.8584],[113.9941,39.9902],[114.5215,40.3418],[114.3457,40.3857],[114.2578,40.6055], + [114.082,40.7373],[113.9063,41.1328],[113.9941,41.2207],[113.9063,41.4404],[114.2578,41.5723],[114.1699,41.792], + [114.5215,42.1436],[114.873,42.0996],[114.9609,41.6162],[115.2246,41.5723],[115.9277,41.9238],[116.0156,41.792], + [116.2793,42.0117],[116.8066,42.0117],[116.8945,42.4072],[117.334,42.4512],[117.5098,42.583],[117.7734,42.627], + [118.0371,42.4072],[117.9492,42.2314],[118.125,42.0557],[118.3008,42.0996],[118.3008,41.792],[118.125,41.748], + [118.3887,41.3086],[119.2676,41.3086],[118.8281,40.8252],[119.2676,40.5176],[119.5313,40.5615],[119.707,40.1221], + [119.8828,39.9463],[119.5313,39.6826],[119.4434,39.4189],[118.916,39.0674],[118.4766,38.9355],[118.125,39.0234], + [118.0371,39.1992],[118.0371,39.2432],[117.8613,39.4189],[117.9492,39.5947],[117.6855,39.5947],[117.5098,39.7705], + [117.5098,39.9902],[117.6855,39.9902],[117.6855,40.0781],[117.4219,40.21],[117.2461,40.5176],[117.4219,40.6494], + [116.9824,40.6934],[116.6309,41.0449],[116.3672,40.9131],[116.4551,40.7813],[116.1914,40.7813],[116.1035,40.6055], + [115.752,40.5615],[115.9277,40.2539],[115.4004,39.9463],[115.4883,39.6387],[115.752,39.5068],[116.1914,39.5947], + [116.3672,39.4629],[116.543,39.5947],[116.8066,39.5947],[116.8945,39.1113],[116.7188,38.9355],[116.7188,38.8037], + [117.2461,38.54],[117.5977,38.6279],[117.9492,38.3203],[117.4219,37.8369],[116.8066,37.8369],[116.4551,37.4854], + [116.2793,37.5732],[116.2793,37.3535],[116.0156,37.3535],[115.752,36.9141],[115.3125,36.5186],[115.4883,36.167], + [115.3125,36.0791],[115.1367,36.2109],[114.9609,36.0791],[114.873,36.123],[113.7305,36.3428],[113.4668,36.6504], + [113.7305,36.8701],[113.7305,37.1338],[114.1699,37.6611],[113.9941,37.7051],[113.8184,38.1445],[113.5547,38.2764], + [113.5547,38.54],[113.8184,38.8037],[113.8184,38.9355],[113.9063,39.0234],[114.3457,39.0674],[114.5215,39.5068] + ] + ], + [ + [ + [117.2461,40.0781],[117.1582,39.8145],[117.1582,39.6387],[116.8945,39.6826],[116.8945,39.8145],[116.8066,39.9902],[117.2461,40.0781] + ] + ] + ] + } + }, + { + "type":"Feature", + "id":"hu_bei", + "properties":{ + "name":"湖北", + "cp":[112.2363,31.1572], + "childNum":17 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [110.2148,31.1572],[110.127,31.377],[109.6875,31.5527],[109.7754,31.6846],[109.5996,31.7285],[109.5117,32.4316], + [109.6875,32.6074],[110.127,32.6074],[110.127,32.7393],[109.7754,32.915],[109.7754,33.0469],[109.4238,33.1348], + [109.5996,33.2666],[110.3027,33.1787],[110.5664,33.2666],[110.7422,33.1348],[111.0059,33.2666],[111.5332,32.6074], + [112.3242,32.3438],[113.2031,32.4316],[113.4668,32.2998],[113.7305,32.4316],[113.8184,31.8604],[113.9941,31.7725], + [114.1699,31.8604],[114.5215,31.7725],[114.6094,31.5527],[114.7852,31.4648],[115.1367,31.5967],[115.2246,31.4209], + [115.4004,31.4209],[115.5762,31.2012],[116.0156,31.0254],[115.752,30.6738],[116.1035,30.1904],[116.1035,29.8389], + [115.9277,29.707],[115.4883,29.7949],[114.873,29.3994],[114.2578,29.3555],[113.9063,29.0479],[113.7305,29.0918], + [113.6426,29.3115],[113.7305,29.5752],[113.5547,29.707],[113.5547,29.8389],[113.0273,29.4434],[112.9395,29.4873], + [113.0273,29.751],[112.9395,29.7949],[112.6758,29.5752],[112.5,29.6191],[112.2363,29.5313],[111.7969,29.9268], + [110.8301,30.1465],[110.4785,30.0146],[110.6543,29.751],[110.4785,29.6631],[109.7754,29.751],[109.6875,29.6191], + [109.5117,29.6191],[109.248,29.1357],[109.0723,29.3555],[108.9844,29.3115],[108.6328,29.8389],[108.457,29.7949], + [108.5449,30.2344],[108.457,30.4102],[108.6328,30.5859],[108.8086,30.498],[109.0723,30.6299],[109.1602,30.542], + [109.248,30.6299],[109.4238,30.542],[109.8633,30.8936],[110.0391,30.8057],[110.2148,31.1572] + ] + ] + } + }, + { + "type":"Feature", + "id":"gui_zhou", + "properties":{ + "name":"贵州", + "cp":[106.6113,26.9385], + "childNum":9 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [104.1504,27.2461], [104.4141,27.4658],[104.5898,27.334],[105.2051,27.3779],[105.293,27.7295],[105.5566,27.7734], + [105.6445,27.6416],[106.3477,27.8174],[106.1719,28.125],[105.9082,28.125],[105.6445,28.4326],[105.9961,28.7402], + [106.3477,28.5205],[106.5234,28.5645],[106.4355,28.7842],[106.5234,28.7842],[106.6113,28.6523],[106.6113,28.5205], + [106.6992,28.4766],[106.875,28.7842],[107.4023,28.8721],[107.4023,29.1797],[107.5781,29.2236],[107.8418,29.1357], + [107.8418,29.0039],[108.2813,29.0918],[108.3691,28.6523],[108.5449,28.6523],[108.5449,28.3887],[108.7207,28.4766], + [108.7207,28.2129],[109.0723,28.2129],[109.248,28.4766],[109.3359,28.2568],[109.3359,27.9053],[109.4238,27.5977], + [108.8086,27.1143],[108.8965,27.0264],[109.3359,27.1582],[109.5117,27.0264],[109.5117,26.8066],[109.3359,26.7188], + [109.4238,26.5869],[109.248,26.3232],[109.4238,26.2793],[109.5117,26.0156],[109.3359,25.708],[108.9844,25.752], + [109.0723,25.5322],[108.6328,25.5762],[108.6328,25.3125],[108.3691,25.5322],[108.1934,25.4443],[108.1055,25.2246], + [107.8418,25.1367],[107.7539,25.2246],[107.4902,25.2246],[107.2266,25.6201],[106.9629,25.4883],[107.0508,25.2686], + [106.875,25.1807],[106.1719,24.9609],[106.1719,24.7852],[105.9961,24.6533],[105.2051,24.9609],[104.6777,24.6094], + [104.502,24.7412],[104.6777,24.9609],[104.5898,25.0488],[104.8535,25.2246],[104.3262,25.708],[104.6777,26.4111], + [104.4141,26.6748],[103.8867,26.543],[103.7109,26.7627],[103.7109,26.9824],[103.623,27.0264],[103.8867,27.4219], + [104.1504,27.2461] + ] + ] + } + }, + { + "type":"Feature", + "id":"shan_dong", + "properties":{ + "name":"山东", + "cp":[118.7402,36.4307], + "childNum":17 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [115.4883,36.167],[115.3125,36.5186],[115.752,36.9141],[116.0156,37.3535],[116.2793,37.3535],[116.2793,37.5732], + [116.4551,37.4854],[116.8066,37.8369],[117.4219,37.8369],[117.9492,38.3203],[118.125,38.1445],[118.916,38.1445], + [119.3555,37.6611],[119.0039,37.5293],[119.0039,37.3535],[119.3555,37.1338],[119.707,37.1338],[119.8828,37.3975], + [120.498,37.8369],[120.5859,38.1445],[120.9375,38.4521],[121.0254,37.8369],[121.2012,37.6611],[121.9043,37.4854], + [122.168,37.6172],[122.2559,37.4854],[122.6074,37.4854],[122.6953,37.3535],[122.6074,36.9141],[122.4316,36.7822], + [121.8164,36.8701],[121.7285,36.6943],[121.1133,36.6064],[121.1133,36.4307],[121.377,36.2549],[120.7617,36.167], + [120.9375,35.8594],[120.6738,36.0352],[119.707,35.4639],[119.9707,34.9805],[119.3555,35.0244],[119.2676,35.1123], + [118.916,35.0244],[118.7402,34.7168],[118.4766,34.6729],[118.3887,34.4092],[118.2129,34.4092],[118.125,34.6289], + [117.9492,34.6729],[117.5977,34.4531],[117.334,34.585],[117.2461,34.4531],[116.8066,34.9365],[116.4551,34.8926], + [116.3672,34.6289],[116.1914,34.585],[115.5762,34.585],[115.4004,34.8486],[114.7852,35.0684],[115.0488,35.376], + [115.2246,35.4199],[115.4883,35.7275],[116.1035,36.0791],[115.3125,35.8154],[115.4883,36.167] + ] + ] + } + }, + { + "type":"Feature", + "id":"jiang_xi", + "properties":{"name":"江西", + "cp":[116.0156,27.29], + "childNum":11}, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [114.2578,28.3447],[114.082,28.5645],[114.1699,28.8281],[113.9063,29.0479],[114.2578,29.3555],[114.873,29.3994], + [115.4883,29.7949],[115.9277,29.707],[116.1035,29.8389],[116.2793,29.7949],[116.7188,30.0586],[116.8945,29.9268], + [116.7188,29.751],[116.7188,29.6191],[117.1582,29.707],[117.0703,29.8389],[117.1582,29.9268],[117.5098,29.6191], + [118.0371,29.5752],[118.2129,29.3994],[118.0371,29.1797],[118.0371,29.0479],[118.3887,28.7842],[118.4766,28.3447], + [118.4766,28.3008],[118.3008,28.0811],[117.7734,27.8174],[117.5098,27.9932],[116.9824,27.6416],[117.1582,27.29], + [117.0703,27.1143],[116.543,26.8066],[116.6309,26.4551],[116.3672,26.2354],[116.4551,26.1035],[116.1914,25.8838], + [116.0156,25.2686],[115.8398,25.2246],[115.9277,24.917],[115.752,24.7852],[115.8398,24.5654],[115.4004,24.7852], + [114.4336,24.5215],[114.1699,24.6973],[114.4336,24.9609],[114.6973,25.1367],[114.7852,25.2686],[114.6094,25.4004], + [113.9941,25.2686],[113.9063,25.4443],[113.9941,26.0596],[114.2578,26.1475],[113.9941,26.1914],[114.082,26.5869], + [113.9063,26.6309],[113.9063,26.9385],[113.7305,27.1143],[113.8184,27.29],[113.6426,27.3779],[113.6426,27.5977], + [113.7305,27.9492],[114.2578,28.3447] + ] + ] + } + }, + { + "type":"Feature", + "id":"he_nan", + "properties":{"name":"河南", + "cp":[113.4668,33.8818], + "childNum":17 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [110.3906,34.585],[110.8301,34.6289],[111.1816,34.8047],[111.5332,34.8486],[111.7969,35.0684],[112.0605,35.0684], + [112.0605,35.2881],[112.7637,35.2002],[113.1152,35.332],[113.6426,35.6836],[113.7305,36.3428],[114.873,36.123], + [114.9609,36.0791],[115.1367,36.2109],[115.3125,36.0791],[115.4883,36.167],[115.3125,35.8154],[116.1035,36.0791], + [115.4883,35.7275],[115.2246,35.4199],[115.0488,35.376],[114.7852,35.0684],[115.4004,34.8486],[115.5762,34.585], + [116.1914,34.585],[116.1914,34.4092],[116.543,34.2773],[116.6309,33.9258],[116.1914,33.7061],[116.0156,33.9697], + [115.6641,34.0576],[115.5762,33.9258],[115.5762,33.6621],[115.4004,33.5303],[115.3125,33.1787],[114.873,33.1348], + [114.873,33.0029],[115.1367,32.8711],[115.2246,32.6074],[115.5762,32.4316],[115.8398,32.5195],[115.9277,31.7725], + [115.4883,31.6846],[115.4004,31.4209],[115.2246,31.4209],[115.1367,31.5967],[114.7852,31.4648],[114.6094,31.5527], + [114.5215,31.7725],[114.1699,31.8604],[113.9941,31.7725],[113.8184,31.8604],[113.7305,32.4316],[113.4668,32.2998], + [113.2031,32.4316],[112.3242,32.3438],[111.5332,32.6074],[111.0059,33.2666],[111.0059,33.5303],[110.6543,33.8379], + [110.6543,34.1455],[110.4785,34.2334],[110.3906,34.585] + ] + ] + } + }, + { + "type":"Feature", + "id":"liao_ning", + "properties":{ + "name":"辽宁", + "cp":[122.3438,41.0889], + "childNum":14 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [119.2676,41.3086],[119.4434,41.6162],[119.2676,41.7041],[119.3555,42.2754],[119.5313,42.3633],[119.8828,42.1875], + [120.1465,41.7041],[120.498,42.0996],[121.4648,42.4951],[121.7285,42.4512],[121.9922,42.7148],[122.3438,42.6709], + [122.3438,42.8467],[122.7832,42.7148],[123.1348,42.8027],[123.3105,42.9785],[123.5742,43.0225],[123.6621,43.374], + [123.8379,43.4619],[124.2773,43.2422],[124.4531,42.8467],[124.7168,43.0664],[124.8926,43.0664],[124.8926,42.8027], + [125.332,42.1436],[125.4199,42.0996],[125.332,41.9678],[125.332,41.6602],[125.7715,41.2207],[125.5957,40.9131], + [125.6836,40.8691],[124.541,40.21],[124.1016,39.6826],[123.3984,39.6826],[123.1348,39.4189],[123.1348,39.0234], + [122.0801,39.0234],[121.5527,38.7158],[121.1133,38.6719],[120.9375,38.9795],[121.377,39.1992],[121.2012,39.5508], + [122.0801,40.3857],[121.9922,40.6934],[121.7285,40.8252],[121.2012,40.8252],[120.5859,40.21],[119.8828,39.9463], + [119.707,40.1221],[119.5313,40.5615],[119.2676,40.5176],[118.8281,40.8252],[119.2676,41.3086] + ] + ] + } + }, + { + "type":"Feature", + "id":"shan_xi_2", + "properties":{"name":"山西", + "cp":[112.4121,37.6611], + "childNum":11 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [110.918,38.7158],[111.1816,39.2432],[111.0938,39.375],[111.3574,39.4189],[111.4453,39.6387],[111.9727,39.5947], + [112.3242,40.2539],[112.7637,40.166],[113.2031,40.3857],[113.5547,40.3418],[113.8184,40.5176],[114.082,40.5176], + [114.082,40.7373],[114.2578,40.6055],[114.3457,40.3857],[114.5215,40.3418],[113.9941,39.9902],[114.3457,39.8584], + [114.5215,39.5068],[114.3457,39.0674],[113.9063,39.0234],[113.8184,38.9355],[113.8184,38.8037],[113.5547,38.54], + [113.5547,38.2764],[113.8184,38.1445],[113.9941,37.7051],[114.1699,37.6611],[113.7305,37.1338],[113.7305,36.8701], + [113.4668,36.6504],[113.7305,36.3428],[113.6426,35.6836],[113.1152,35.332],[112.7637,35.2002],[112.0605,35.2881], + [112.0605,35.0684],[111.7969,35.0684],[111.5332,34.8486],[111.1816,34.8047],[110.8301,34.6289],[110.3906,34.585], + [110.2148,34.6729],[110.2148,34.8926],[110.5664,35.6396],[110.4785,36.123],[110.3906,37.002],[110.8301,37.6611], + [110.4785,37.9688],[110.4785,38.1885],[110.8301,38.4961],[110.918,38.7158] + ] + ] + } + }, + { + "type":"Feature", + "id":"an_hui", + "properties":{"name":"安徽", + "cp":[117.2461,32.0361], + "childNum":17 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [116.6309,33.9258],[116.543,34.2773],[116.1914,34.4092],[116.1914,34.585],[116.3672,34.6289],[116.8945,34.4092], + [117.1582,34.0576],[117.5977,34.0137],[117.7734,33.7061],[118.125,33.75],[117.9492,33.2227],[118.0371,33.1348], + [118.2129,33.2227],[118.3008,32.7832],[118.7402,32.7393],[118.916,32.959],[119.1797,32.8271],[119.1797,32.4756], + [118.5645,32.5635],[118.6523,32.2119],[118.4766,32.168],[118.3887,31.9482],[118.916,31.5527],[118.7402,31.377], + [118.8281,31.2451],[119.3555,31.2891],[119.4434,31.1572],[119.6191,31.1133],[119.6191,31.0693],[119.4434,30.6738], + [119.2676,30.6299],[119.3555,30.4102],[118.916,30.3223],[118.916,29.9707],[118.7402,29.707],[118.2129,29.3994], + [118.0371,29.5752],[117.5098,29.6191],[117.1582,29.9268],[117.0703,29.8389],[117.1582,29.707],[116.7188,29.6191], + [116.7188,29.751],[116.8945,29.9268],[116.7188,30.0586],[116.2793,29.7949],[116.1035,29.8389],[116.1035,30.1904], + [115.752,30.6738],[116.0156,31.0254],[115.5762,31.2012],[115.4004,31.4209],[115.4883,31.6846],[115.9277,31.7725], + [115.8398,32.5195],[115.5762,32.4316],[115.2246,32.6074],[115.1367,32.8711],[114.873,33.0029],[114.873,33.1348], + [115.3125,33.1787],[115.4004,33.5303],[115.5762,33.6621],[115.5762,33.9258],[115.6641,34.0576],[116.0156,33.9697], + [116.1914,33.7061],[116.6309,33.9258] + ] + ] + } + }, + { + "type":"Feature", + "id":"fu_jian", + "properties":{ + "name":"福建", + "cp":[118.3008,25.9277], + "childNum":9 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [118.4766,28.3008],[118.8281,28.2568],[118.7402,28.0371],[118.916,27.4658],[119.2676,27.4219],[119.6191,27.6855], + [119.7949,27.29],[120.2344,27.4219],[120.4102,27.1582],[120.7617,27.0264],[120.6738,26.8945],[120.2344,26.8506], + [120.2344,26.7188],[120.4102,26.6748],[120.498,26.3672],[120.2344,26.2793],[120.4102,26.1475],[120.0586,26.1914], + [119.9707,25.9277],[119.7949,25.9277],[119.9707,25.4004],[119.7949,25.2686],[119.5313,25.1367],[119.4434,25.0049], + [119.2676,25.0928],[118.916,24.8291],[118.6523,24.5215],[118.4766,24.5215],[118.4766,24.4336],[118.2129,24.3457], + [118.2129,24.1699],[117.8613,23.9941],[117.7734,23.7744],[117.5098,23.5986],[117.1582,23.5547],[116.9824,23.9063], + [116.9824,24.1699],[116.7188,24.6533],[116.543,24.6094],[116.3672,24.873],[116.2793,24.7852],[115.9277,24.917], + [115.8398,25.2246],[116.0156,25.2686],[116.1914,25.8838],[116.4551,26.1035],[116.3672,26.2354],[116.6309,26.4551], + [116.543,26.8066],[117.0703,27.1143],[117.1582,27.29],[116.9824,27.6416],[117.5098,27.9932],[117.7734,27.8174], + [118.3008,28.0811],[118.4766,28.3008] + ] + ] + } + }, + { + "type":"Feature", + "id":"zhe_jiang", + "properties":{ + "name":"浙江", + "cp":[120.498,29.0918], + "childNum":11 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [118.2129,29.3994],[118.7402,29.707],[118.916,29.9707],[118.916,30.3223],[119.3555,30.4102],[119.2676,30.6299], + [119.4434,30.6738],[119.6191,31.0693],[119.6191,31.1133],[119.9707,31.1572],[120.498,30.8057],[120.9375,31.0254], + [121.2891,30.6738],[121.9922,30.8057],[122.6953,30.8936],[122.8711,30.7178],[122.959,30.1465],[122.6074,30.1025], + [122.6074,29.9268],[122.168,29.5313],[122.3438,28.8721],[121.9922,28.8721],[121.9922,28.4326],[121.7285,28.3447], + [121.7285,28.2129],[121.4648,28.2129],[121.5527,28.0371],[121.2891,27.9492],[121.1133,27.4219],[120.6738,27.334], + [120.6738,27.1582],[120.9375,27.0264],[120.7617,27.0264],[120.4102,27.1582],[120.2344,27.4219],[119.7949,27.29], + [119.6191,27.6855],[119.2676,27.4219],[118.916,27.4658],[118.7402,28.0371],[118.8281,28.2568],[118.4766,28.3008], + [118.4766,28.3447],[118.3887,28.7842],[118.0371,29.0479],[118.0371,29.1797],[118.2129,29.3994] + ] + ] + } + }, + { + "type":"Feature", + "id":"jiang_su", + "properties":{ + "name":"江苏", + "cp":[120.0586,32.915], + "childNum":13 + },"geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [116.3672,34.6289],[116.4551,34.8926],[116.8066,34.9365],[117.2461,34.4531],[117.334,34.585],[117.5977,34.4531], + [117.9492,34.6729],[118.125,34.6289],[118.2129,34.4092],[118.3887,34.4092],[118.4766,34.6729],[118.7402,34.7168], + [118.916,35.0244],[119.2676,35.1123],[119.3555,35.0244],[119.3555,34.8486],[119.707,34.585],[120.3223,34.3652], + [120.9375,33.0469],[121.0254,32.6514],[121.377,32.4756],[121.4648,32.168],[121.9043,31.9922],[121.9922,31.6846], + [121.9922,31.5967],[121.2012,31.8604],[121.1133,31.7285],[121.377,31.5088],[121.2012,31.4648],[120.9375,31.0254], + [120.498,30.8057],[119.9707,31.1572],[119.6191,31.1133],[119.4434,31.1572],[119.3555,31.2891],[118.8281,31.2451], + [118.7402,31.377],[118.916,31.5527],[118.3887,31.9482],[118.4766,32.168],[118.6523,32.2119],[118.5645,32.5635], + [119.1797,32.4756],[119.1797,32.8271],[118.916,32.959],[118.7402,32.7393],[118.3008,32.7832],[118.2129,33.2227], + [118.0371,33.1348],[117.9492,33.2227],[118.125,33.75],[117.7734,33.7061],[117.5977,34.0137],[117.1582,34.0576], + [116.8945,34.4092],[116.3672,34.6289] + ] + ] + } + }, + { + "type":"Feature", + "id":"chong_qing", + "properties":{ + "name":"重庆", + "cp":[107.7539,30.1904], + "childNum":40 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [108.5449,31.6846],[108.2813,31.9043],[108.3691,32.168],[108.5449,32.2119],[109.0723,31.9482],[109.248,31.7285], + [109.5996,31.7285],[109.7754,31.6846],[109.6875,31.5527],[110.127,31.377],[110.2148,31.1572],[110.0391,30.8057], + [109.8633,30.8936],[109.4238,30.542],[109.248,30.6299],[109.1602,30.542],[109.0723,30.6299],[108.8086,30.498], + [108.6328,30.5859],[108.457,30.4102],[108.5449,30.2344],[108.457,29.7949],[108.6328,29.8389],[108.9844,29.3115], + [109.0723,29.3555],[109.248,29.1357],[109.248,28.4766],[109.0723,28.2129],[108.7207,28.2129],[108.7207,28.4766], + [108.5449,28.3887],[108.5449,28.6523],[108.3691,28.6523],[108.2813,29.0918],[107.8418,29.0039],[107.8418,29.1357], + [107.5781,29.2236],[107.4023,29.1797],[107.4023,28.8721],[106.875,28.7842],[106.6992,28.4766],[106.6113,28.5205], + [106.6113,28.6523],[106.5234,28.7842],[106.4355,28.7842],[106.5234,28.5645],[106.3477,28.5205],[106.2598,28.8721], + [105.8203,28.96],[105.7324,29.2676],[105.4688,29.3115],[105.293,29.5313],[105.7324,29.8828],[105.5566,30.1025], + [105.6445,30.2783],[105.8203,30.4541],[106.2598,30.1904],[106.6113,30.3223],[106.7871,30.0146],[107.0508,30.0146], + [107.4902,30.6299],[107.4023,30.7617],[107.4902,30.8496],[107.9297,30.8496],[108.1934,31.5088],[108.5449,31.6846] + ] + ] + } + }, + { + "type":"Feature", + "id":"ning_xia", + "properties":{ + "name":"宁夏", + "cp":[105.9961,37.3096], + "childNum":5 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [104.3262,37.4414],[105.8203,37.793],[105.9082,38.7158],[106.3477,39.2871],[106.7871,39.375],[106.9629,38.9795], + [106.5234,38.3203],[106.7871,38.1885],[107.3145,38.1006],[107.666,37.8809],[107.3145,37.6172],[107.3145,37.0898], + [106.6113,37.0898],[106.6113,36.7822],[106.4355,36.5625],[106.5234,36.4746],[106.5234,36.2549],[106.875,36.123], + [106.9629,35.8154],[106.6992,35.6836],[106.4355,35.6836],[106.5234,35.332],[106.3477,35.2441],[106.2598,35.4199], + [106.084,35.376],[105.9961,35.4199],[106.084,35.4639],[105.9961,35.4639],[105.8203,35.5518],[105.7324,35.7275], + [105.3809,35.7715],[105.293,35.9912],[105.4688,36.123],[105.2051,36.6943],[105.293,36.8262],[104.8535,37.2217], + [104.5898,37.2217],[104.5898,37.4414],[104.3262,37.4414] + ] + ] + } + }, + { + "type":"Feature", + "id":"hai_nan", + "properties":{ + "name":"海南", + "cp":[109.9512,19.2041], + "childNum":18 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [108.6328,19.3799],[109.0723,19.6436],[109.248,19.9512],[109.5996,20.0391],[110.0391,20.127],[110.3906,20.127], + [110.5664,20.2588],[110.6543,20.2588],[111.0938,19.9512],[111.2695,19.9951],[110.6543,19.1602],[110.5664,18.6768], + [110.2148,18.5889],[110.0391,18.3691],[109.8633,18.3691],[109.6875,18.1055],[108.9844,18.2813],[108.6328,18.457], + [108.6328,19.3799] + ] + ] + } + }, + { + "type":"Feature", + "id":"tai_wan", + "properties":{ + "name":"台湾", + "cp":[121.0254,23.5986], + "childNum":1 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [121.9043,25.0488],[121.9922,25.0049],[121.8164,24.7412],[121.9043,24.5654],[121.6406,24.0381],[121.377,23.1152], + [121.0254,22.6758],[120.8496,22.0605],[120.7617,21.9287],[120.6738,22.3242],[120.2344,22.5879],[120.0586,23.0713], + [120.1465,23.6865],[121.0254,25.0488],[121.5527,25.3125],[121.9043,25.0488] + ] + ] + } + }, + { + "type":"Feature", + "id":"bei_jing", + "properties":{ + "name":"北京", + "cp":[116.4551,40.2539], + "childNum":19 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [117.4219,40.21],[117.334,40.1221],[117.2461,40.0781],[116.8066,39.9902],[116.8945,39.8145],[116.8945,39.6826], + [116.8066,39.5947],[116.543,39.5947],[116.3672,39.4629],[116.1914,39.5947],[115.752,39.5068],[115.4883,39.6387], + [115.4004,39.9463],[115.9277,40.2539],[115.752,40.5615],[116.1035,40.6055],[116.1914,40.7813],[116.4551,40.7813], + [116.3672,40.9131],[116.6309,41.0449],[116.9824,40.6934],[117.4219,40.6494],[117.2461,40.5176],[117.4219,40.21] + ] + ] + } + }, + { + "type":"Feature", + "id":"tian_jin", + "properties":{ + "name":"天津", + "cp":[117.4219,39.4189], + "childNum":18 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [116.8066,39.5947],[116.8945,39.6826],[117.1582,39.6387],[117.1582,39.8145],[117.2461,40.0781],[117.334,40.1221], + [117.4219,40.21],[117.6855,40.0781],[117.6855,39.9902],[117.5098,39.9902],[117.5098,39.7705],[117.6855,39.5947], + [117.9492,39.5947],[117.8613,39.4189],[118.0371,39.2432],[118.0371,39.1992],[117.8613,39.1113],[117.5977,38.6279], + [117.2461,38.54],[116.7188,38.8037],[116.7188,38.9355],[116.8945,39.1113],[116.8066,39.5947] + ] + ] + } + }, + { + "type":"Feature", + "id":"shang_hai", + "properties":{ + "name":"上海", + "cp":[121.4648,31.2891], + "childNum":19 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [[120.9375,31.0254],[121.2012,31.4648],[121.377,31.5088],[121.1133,31.7285],[121.2012,31.8604],[121.9922,31.5967], + [121.9043,31.1572],[121.9922,30.8057],[121.2891,30.6738],[120.9375,31.0254] + ] + ] + } + }, + { + "type":"Feature", + "id":"xiang_gang", + "properties":{ + "name":"香港", + "cp":[114.2578,22.3242], + "childNum":1 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [114.6094,22.4121],[114.5215,22.1484],[114.3457,22.1484],[113.9063,22.1484],[113.8184,22.1924],[113.9063,22.4121], + [114.1699,22.5439],[114.3457,22.5439],[114.4336,22.5439],[114.4336,22.4121],[114.6094,22.4121] + ] + ] + } + }, + { + "type":"Feature", + "id":"ao_men", + "properties":{ + "name":"澳门", + "cp":[113.5547,22.1484], + "childNum":1 + }, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [113.5986,22.1649],[113.6096,22.1265],[113.5547,22.11],[113.5437,22.2034],[113.5767,22.2034],[113.5986,22.1649] + ] + ] + } + } + ] + }
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/public/sjData/word.json b/UI source code/dns_mapping_ui-master/public/sjData/word.json new file mode 100644 index 0000000..57e343d --- /dev/null +++ b/UI source code/dns_mapping_ui-master/public/sjData/word.json @@ -0,0 +1,194 @@ +{ + "status": true, + "namemap": { + "Afghanistan": "阿富汗", + "Angola": "安哥拉", + "Albania": "阿尔巴尼亚", + "Algeria": "阿尔及利亚", + "Argentina": "阿根廷", + "Armenia": "亚美尼亚", + "Australia": "澳大利亚", + "Austria": "奥地利", + "Azerbaijan": "阿塞拜疆", + "Bahamas": "巴哈马", + "Bangladesh": "孟加拉国", + "Belgium": "比利时", + "Benin": "贝宁", + "Burkina Faso": "布基纳法索", + "Burundi": "布隆迪", + "Bulgaria": "保加利亚", + "Bosnia and Herz.": "波斯尼亚和黑塞哥维那", + "Belarus": "白俄罗斯", + "Belize": "伯利兹", + "Bermuda": "百慕大群岛", + "Bolivia": "玻利维亚", + "Brazil": "巴西", + "Brunei": "文莱", + "Bhutan": "不丹", + "Botswana": "博茨瓦纳", + "Cambodia": "柬埔寨", + "Cameroon": "喀麦隆", + "Canada": "加拿大", + "Central African Rep.": "中非共和国", + "Chad": "乍得", + "Chile": "智利", + "China": "中国", + "Colombia": "哥伦比亚", + "Congo": "刚果", + "Costa Rica": "哥斯达黎加", + "Côte d'Ivoire": "科特迪瓦", + "Croatia": "克罗地亚", + "Cuba": "古巴", + "Cyprus": "塞浦路斯", + "Czech Rep.": "捷克共和国", + "Dem. Rep. Korea": "韩国", + "Dem. Rep. Congo": "民主刚果", + "Denmark": "丹麦", + "Djibouti": "吉布提", + "Dominican Rep.": "多米尼加共和国", + "Ecuador": "厄瓜多尔", + "Egypt": "埃及", + "El Salvador": "萨尔瓦多", + "Eq. Guinea": "赤道几内亚", + "Eritrea": "厄立特里亚", + "Estonia": "爱沙尼亚", + "Ethiopia": "埃塞俄比亚", + "Falkland Is.": "福克兰群岛", + "Fiji": "斐济", + "Finland": "芬兰", + "France": "法国", + "French Guiana": "法属圭亚那", + "Fr. S. Antarctic Lands": "法属南部领地", + "Gabon": "加蓬", + "Gambia": "冈比亚", + "Germany": "德国", + "Georgia": "佐治亚州", + "Ghana": "加纳", + "Greece": "希腊", + "Greenland": "格陵兰", + "Guatemala": "危地马拉", + "Guinea": "几内亚", + "Guinea-Bissau": "几内亚比绍", + "Guyana": "圭亚那", + "Haiti": "海地", + "Heard I. and McDonald Is.": "赫德岛和麦克唐纳群岛", + "Honduras": "洪都拉斯", + "Hungary": "匈牙利", + "Iceland": "冰岛", + "India": "印度", + "Indonesia": "印度尼西亚", + "Iran": "伊朗", + "Iraq": "伊拉克", + "Ireland": "爱尔兰", + "Israel": "以色列", + "Italy": "意大利", + "Ivory Coast": "象牙海岸", + "Jamaica": "牙买加", + "Japan": "日本", + "Jordan": "乔丹", + "Kashmir": "克什米尔", + "Kazakhstan": "哈萨克斯坦", + "Kenya": "肯尼亚", + "Kosovo": "科索沃", + "Kuwait": "科威特", + "Kyrgyzstan": "吉尔吉斯斯坦", + "Laos": "老挝", + "Lao PDR": "老挝人民民主共和国", + "Latvia": "拉脱维亚", + "Lebanon": "黎巴嫩", + "Lesotho": "莱索托", + "Liberia": "利比里亚", + "Libya": "利比亚", + "Lithuania": "立陶宛", + "Luxembourg": "卢森堡", + "Madagascar": "马达加斯加", + "Macedonia": "马其顿", + "Malawi": "马拉维", + "Malaysia": "马来西亚", + "Mali": "马里", + "Mauritania": "毛里塔尼亚", + "Mexico": "墨西哥", + "Moldova": "摩尔多瓦", + "Mongolia": "蒙古", + "Montenegro": "黑山", + "Morocco": "摩洛哥", + "Mozambique": "莫桑比克", + "Myanmar": "缅甸", + "Namibia": "纳米比亚", + "Netherlands": "荷兰", + "New Caledonia": "新喀里多尼亚", + "New Zealand": "新西兰", + "Nepal": "尼泊尔", + "Nicaragua": "尼加拉瓜", + "Niger": "尼日尔", + "Nigeria": "尼日利亚", + "Korea": "朝鲜", + "Northern Cyprus": "北塞浦路斯", + "Norway": "挪威", + "Oman": "阿曼", + "Pakistan": "巴基斯坦", + "Panama": "巴拿马", + "Papua New Guinea": "巴布亚新几内亚", + "Paraguay": "巴拉圭", + "Peru": "秘鲁", + "Republic of the Congo": "刚果共和国", + "Philippines": "菲律宾", + "Poland": "波兰", + "Portugal": "葡萄牙", + "Puerto Rico": "波多黎各", + "Qatar": "卡塔尔", + "Republic of Seychelles": "塞舌尔共和国", + "Romania": "罗马尼亚", + "Russia": "俄罗斯", + "Rwanda": "卢旺达", + "Samoa": "萨摩亚", + "Saudi Arabia": "沙特阿拉伯", + "Senegal": "塞内加尔", + "Serbia": "塞尔维亚", + "Sierra Leone": "塞拉利昂", + "Slovakia": "斯洛伐克", + "Slovenia": "斯洛文尼亚", + "Solomon Is.": "所罗门群岛", + "Somaliland": "索马里兰", + "Somalia": "索马里", + "South Africa": "南非", + "S. Geo. and S. Sandw. Is.": "南乔治亚和南桑德威奇群岛", + "S. Sudan": "南苏丹", + "Spain": "西班牙", + "Sri Lanka": "斯里兰卡", + "Sudan": "苏丹", + "Suriname": "苏里南", + "Swaziland": "斯威士兰", + "Sweden": "瑞典", + "Switzerland": "瑞士", + "Syria": "叙利亚", + "Tajikistan": "塔吉克斯坦", + "Tanzania": "坦桑尼亚", + "Thailand": "泰国", + "The Kingdom of Tonga": "汤加王国", + "Timor-Leste": "东帝汶", + "Togo": "多哥", + "Trinidad and Tobago": "特立尼达和多巴哥", + "Tunisia": "突尼斯", + "Turkey": "土耳其", + "Turkmenistan": "土库曼斯坦", + "Uganda": "乌干达", + "Ukraine": "乌克兰", + "United Arab Emirates": "阿拉伯联合酋长国", + "United Kingdom": "大不列颠联合王国", + "United Republic of Tanzania": "坦桑尼亚联合共和国", + "United States": "美国", + "United States of America": "美利坚合众国", + "Uruguay": "乌拉圭", + "Uzbekistan": "乌兹别克斯坦", + "Vanuatu": "瓦努阿图", + "Venezuela": "委内瑞拉", + "Vietnam": "越南", + "West Bank": "西岸", + "W. Sahara": "西撒哈拉", + "Yemen": "也门", + "Zambia": "赞比亚", + "Zimbabwe": "津巴布韦" + }, + "dataArr": [] + }
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/App.vue b/UI source code/dns_mapping_ui-master/src/App.vue new file mode 100644 index 0000000..ec9032c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/App.vue @@ -0,0 +1,11 @@ +<template> + <div id="app"> + <router-view /> + </div> +</template> + +<script> +export default { + name: 'App' +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/api/data.js b/UI source code/dns_mapping_ui-master/src/api/data.js new file mode 100644 index 0000000..d975d75 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/data.js @@ -0,0 +1,17 @@ +import request from '@/utils/request' +import qs from 'qs' + +export function initData(url, params) { + return request({ + url: url + '?' + qs.stringify(params, { indices: false }), + method: 'get' + }) +} + +export function download(url, params) { + return request({ + url: url + '?' + qs.stringify(params, { indices: false }), + method: 'get', + responseType: 'blob' + }) +} diff --git a/UI source code/dns_mapping_ui-master/src/api/generator/genConfig.js b/UI source code/dns_mapping_ui-master/src/api/generator/genConfig.js new file mode 100644 index 0000000..e15b200 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/generator/genConfig.js @@ -0,0 +1,16 @@ +import request from '@/utils/request' + +export function get(tableName) { + return request({ + url: 'api/genConfig/' + tableName, + method: 'get' + }) +} + +export function update(data) { + return request({ + url: 'api/genConfig', + data, + method: 'put' + }) +} diff --git a/UI source code/dns_mapping_ui-master/src/api/generator/generator.js b/UI source code/dns_mapping_ui-master/src/api/generator/generator.js new file mode 100644 index 0000000..0c49718 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/generator/generator.js @@ -0,0 +1,33 @@ +import request from '@/utils/request' + +export function getAllTable() { + return request({ + url: 'api/generator/tables/all', + method: 'get' + }) +} + +export function generator(tableName, type) { + return request({ + url: 'api/generator/' + tableName + '/' + type, + method: 'post', + responseType: type === 2 ? 'blob' : '' + }) +} + +export function save(data) { + return request({ + url: 'api/generator', + data, + method: 'put' + }) +} + +export function sync(tables) { + return request({ + url: 'api/generator/sync', + method: 'post', + data: tables + }) +} + diff --git a/UI source code/dns_mapping_ui-master/src/api/login.js b/UI source code/dns_mapping_ui-master/src/api/login.js new file mode 100644 index 0000000..bdafcbc --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/login.js @@ -0,0 +1,36 @@ +import request from '@/utils/request' + +export function login(username, password, code, uuid) { + return request({ + url: 'auth/login', + method: 'post', + data: { + username, + password, + code, + uuid + } + }) +} + +export function getInfo() { + return request({ + url: 'auth/info', + method: 'get' + }) +} + +export function getCodeImg() { + return request({ + url: 'auth/code', + method: 'get' + }) +} + +export function logout() { + return request({ + url: 'auth/logout', + method: 'delete' + }) +} + diff --git a/UI source code/dns_mapping_ui-master/src/api/mnt/app.js b/UI source code/dns_mapping_ui-master/src/api/mnt/app.js new file mode 100644 index 0000000..2a27054 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/mnt/app.js @@ -0,0 +1,27 @@ +import request from '@/utils/request' + +export function add(data) { + return request({ + url: 'api/app', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/app', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/app', + method: 'put', + data + }) +} + +export default { add, edit, del } diff --git a/UI source code/dns_mapping_ui-master/src/api/mnt/connect.js b/UI source code/dns_mapping_ui-master/src/api/mnt/connect.js new file mode 100644 index 0000000..1bbe90b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/mnt/connect.js @@ -0,0 +1,17 @@ +import request from '@/utils/request' + +export function testDbConnect(data) { + return request({ + url: 'api/database/testConnect', + method: 'post', + data + }) +} + +export function testServerConnect(data) { + return request({ + url: 'api/serverDeploy/testConnect', + method: 'post', + data + }) +} diff --git a/UI source code/dns_mapping_ui-master/src/api/mnt/database.js b/UI source code/dns_mapping_ui-master/src/api/mnt/database.js new file mode 100644 index 0000000..91797fb --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/mnt/database.js @@ -0,0 +1,35 @@ +import request from '@/utils/request' + +export function add(data) { + return request({ + url: 'api/database', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/database', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/database', + method: 'put', + data + }) +} + +export function testDbConnection(data) { + return request({ + url: 'api/database/testConnect', + method: 'post', + data + }) +} + +export default { add, edit, del, testDbConnection } diff --git a/UI source code/dns_mapping_ui-master/src/api/mnt/deploy.js b/UI source code/dns_mapping_ui-master/src/api/mnt/deploy.js new file mode 100644 index 0000000..c1475ea --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/mnt/deploy.js @@ -0,0 +1,77 @@ +import request from '@/utils/request' + +export function add(data) { + return request({ + url: 'api/deploy', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/deploy', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/deploy', + method: 'put', + data + }) +} + +export function getApps() { + return request({ + url: 'api/app', + method: 'get' + }) +} + +export function getServers() { + return request({ + url: 'api/serverDeploy', + method: 'get' + }) +} + +/** + * 启动服务 + * @param data 选中行 + */ +export function startServer(data) { + return request({ + url: 'api/deploy/startServer', + method: 'post', + data + }) +} + +/** + * 停止服务 + * @param data 选中行 + */ +export function stopServer(data) { + return request({ + url: 'api/deploy/stopServer', + method: 'post', + data + }) +} + +/** + * 停止服务 + * @param data 选中行 + */ +export function serverStatus(data) { + return request({ + url: 'api/deploy/serverStatus', + method: 'post', + data + }) +} + +export default { add, edit, del, stopServer, serverStatus, startServer, getServers, getApps } diff --git a/UI source code/dns_mapping_ui-master/src/api/mnt/deployHistory.js b/UI source code/dns_mapping_ui-master/src/api/mnt/deployHistory.js new file mode 100644 index 0000000..30335e4 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/mnt/deployHistory.js @@ -0,0 +1,21 @@ +import request from '@/utils/request' + +export function del(ids) { + return request({ + url: 'api/deployHistory', + method: 'delete', + data: ids + }) +} + +/** + * 版本回退 + * @param data 选中行 + */ +export function reducte(data) { + return request({ + url: 'api/deploy/serverReduction', + method: 'post', + data + }) +} diff --git a/UI source code/dns_mapping_ui-master/src/api/mnt/serverDeploy.js b/UI source code/dns_mapping_ui-master/src/api/mnt/serverDeploy.js new file mode 100644 index 0000000..e796114 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/mnt/serverDeploy.js @@ -0,0 +1,27 @@ +import request from '@/utils/request' + +export function add(data) { + return request({ + url: 'api/serverDeploy', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/serverDeploy', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/serverDeploy', + method: 'put', + data + }) +} + +export default { add, edit, del } diff --git a/UI source code/dns_mapping_ui-master/src/api/monitor/log.js b/UI source code/dns_mapping_ui-master/src/api/monitor/log.js new file mode 100644 index 0000000..13f0d39 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/monitor/log.js @@ -0,0 +1,22 @@ +import request from '@/utils/request' + +export function getErrDetail(id) { + return request({ + url: 'api/logs/error/' + id, + method: 'get' + }) +} + +export function delAllError() { + return request({ + url: 'api/logs/del/error', + method: 'delete' + }) +} + +export function delAllInfo() { + return request({ + url: 'api/logs/del/info', + method: 'delete' + }) +} diff --git a/UI source code/dns_mapping_ui-master/src/api/monitor/online.js b/UI source code/dns_mapping_ui-master/src/api/monitor/online.js new file mode 100644 index 0000000..057275b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/monitor/online.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +export function del(keys) { + return request({ + url: 'auth/online', + method: 'delete', + data: keys + }) +} diff --git a/UI source code/dns_mapping_ui-master/src/api/search.js b/UI source code/dns_mapping_ui-master/src/api/search.js new file mode 100644 index 0000000..aafc4ac --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/search.js @@ -0,0 +1,25 @@ +import request from '@/utils/request' + +export function getsearchList(params) { + return request({ + url: '/dns', + method: 'get', + params + }) +} + +export function getleftList(params) { + return request({ + url: '/dns/dataCount', + method: 'get', + params + }) +} + +export function getmapList(params) { + return request({ + url: '/dns/mapData', + method: 'get', + params + }) +}
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/api/system/code.js b/UI source code/dns_mapping_ui-master/src/api/system/code.js new file mode 100644 index 0000000..0d2e4c2 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/system/code.js @@ -0,0 +1,15 @@ +import request from '@/utils/request' + +export function resetEmail(data) { + return request({ + url: 'api/code/resetEmail?email=' + data, + method: 'post' + }) +} + +export function updatePass(pass) { + return request({ + url: 'api/users/updatePass/' + pass, + method: 'get' + }) +} diff --git a/UI source code/dns_mapping_ui-master/src/api/system/dept.js b/UI source code/dns_mapping_ui-master/src/api/system/dept.js new file mode 100644 index 0000000..ed4f944 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/system/dept.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +export function getDepts(params) { + return request({ + url: 'api/dept', + method: 'get', + params + }) +} + +export function getDeptSuperior(ids) { + const data = ids.length || ids.length === 0 ? ids : Array.of(ids) + return request({ + url: 'api/dept/superior', + method: 'post', + data + }) +} + +export function add(data) { + return request({ + url: 'api/dept', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/dept', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/dept', + method: 'put', + data + }) +} + +export default { add, edit, del, getDepts, getDeptSuperior } diff --git a/UI source code/dns_mapping_ui-master/src/api/system/dict.js b/UI source code/dns_mapping_ui-master/src/api/system/dict.js new file mode 100644 index 0000000..99170f7 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/system/dict.js @@ -0,0 +1,34 @@ +import request from '@/utils/request' + +export function getDicts() { + return request({ + url: 'api/dict/all', + method: 'get' + }) +} + +export function add(data) { + return request({ + url: 'api/dict', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/dict/', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/dict', + method: 'put', + data + }) +} + +export default { add, edit, del } diff --git a/UI source code/dns_mapping_ui-master/src/api/system/dictDetail.js b/UI source code/dns_mapping_ui-master/src/api/system/dictDetail.js new file mode 100644 index 0000000..e8dc512 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/system/dictDetail.js @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +export function get(dictName) { + const params = { + dictName, + page: 0, + size: 9999 + } + return request({ + url: 'api/dictDetail', + method: 'get', + params + }) +} + +export function getDictMap(dictName) { + const params = { + dictName, + page: 0, + size: 9999 + } + return request({ + url: 'api/dictDetail/map', + method: 'get', + params + }) +} + +export function add(data) { + return request({ + url: 'api/dictDetail', + method: 'post', + data + }) +} + +export function del(id) { + return request({ + url: 'api/dictDetail/' + id, + method: 'delete' + }) +} + +export function edit(data) { + return request({ + url: 'api/dictDetail', + method: 'put', + data + }) +} + +export default { add, edit, del } diff --git a/UI source code/dns_mapping_ui-master/src/api/system/job.js b/UI source code/dns_mapping_ui-master/src/api/system/job.js new file mode 100644 index 0000000..a00630e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/system/job.js @@ -0,0 +1,40 @@ +import request from '@/utils/request' + +export function getAllJob() { + const params = { + page: 0, + size: 9999, + enabled: true + } + return request({ + url: 'api/job', + method: 'get', + params + }) +} + +export function add(data) { + return request({ + url: 'api/job', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/job', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/job', + method: 'put', + data + }) +} + +export default { add, edit, del } diff --git a/UI source code/dns_mapping_ui-master/src/api/system/menu.js b/UI source code/dns_mapping_ui-master/src/api/system/menu.js new file mode 100644 index 0000000..282dd8d --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/system/menu.js @@ -0,0 +1,65 @@ +import request from '@/utils/request' + +export function getMenusTree(pid) { + return request({ + url: 'api/menus/lazy?pid=' + pid, + method: 'get' + }) +} + +export function getMenus(params) { + return request({ + url: 'api/menus', + method: 'get', + params + }) +} + +export function getMenuSuperior(ids) { + const data = Array.isArray(ids) || ids.length === 0 ? ids : Array.of(ids) + return request({ + url: 'api/menus/superior', + method: 'post', + data + }) +} + +export function getChild(id) { + return request({ + url: 'api/menus/child?id=' + id, + method: 'get' + }) +} + +export function buildMenus() { + return request({ + url: 'api/menus/build', + method: 'get' + }) +} + +export function add(data) { + return request({ + url: 'api/menus', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/menus', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/menus', + method: 'put', + data + }) +} + +export default { add, edit, del, getMenusTree, getMenuSuperior, getMenus, getChild } diff --git a/UI source code/dns_mapping_ui-master/src/api/system/role.js b/UI source code/dns_mapping_ui-master/src/api/system/role.js new file mode 100644 index 0000000..1f7bc1e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/system/role.js @@ -0,0 +1,57 @@ +import request from '@/utils/request' + +// 获取所有的Role +export function getAll() { + return request({ + url: 'api/roles/all', + method: 'get' + }) +} + +export function add(data) { + return request({ + url: 'api/roles', + method: 'post', + data + }) +} + +export function get(id) { + return request({ + url: 'api/roles/' + id, + method: 'get' + }) +} + +export function getLevel() { + return request({ + url: 'api/roles/level', + method: 'get' + }) +} + +export function del(ids) { + return request({ + url: 'api/roles', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/roles', + method: 'put', + data + }) +} + +export function editMenu(data) { + return request({ + url: 'api/roles/menu', + method: 'put', + data + }) +} + +export default { add, edit, del, get, editMenu, getLevel } diff --git a/UI source code/dns_mapping_ui-master/src/api/system/timing.js b/UI source code/dns_mapping_ui-master/src/api/system/timing.js new file mode 100644 index 0000000..613e15f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/system/timing.js @@ -0,0 +1,41 @@ +import request from '@/utils/request' + +export function add(data) { + return request({ + url: 'api/jobs', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/jobs', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/jobs', + method: 'put', + data + }) +} + +export function updateIsPause(id) { + return request({ + url: 'api/jobs/' + id, + method: 'put' + }) +} + +export function execution(id) { + return request({ + url: 'api/jobs/exec/' + id, + method: 'put' + }) +} + +export default { del, updateIsPause, execution, add, edit } diff --git a/UI source code/dns_mapping_ui-master/src/api/system/user.js b/UI source code/dns_mapping_ui-master/src/api/system/user.js new file mode 100644 index 0000000..6cd91a5 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/system/user.js @@ -0,0 +1,61 @@ +import request from '@/utils/request' +import { encrypt } from '@/utils/rsaEncrypt' + +export function add(data) { + return request({ + url: 'api/users', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/users', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/users', + method: 'put', + data + }) +} + +export function editUser(data) { + return request({ + url: 'api/users/center', + method: 'put', + data + }) +} + +export function updatePass(user) { + const data = { + oldPass: encrypt(user.oldPass), + newPass: encrypt(user.newPass) + } + return request({ + url: 'api/users/updatePass/', + method: 'post', + data + }) +} + +export function updateEmail(form) { + const data = { + password: encrypt(form.pass), + email: form.email + } + return request({ + url: 'api/users/updateEmail/' + form.code, + method: 'post', + data + }) +} + +export default { add, edit, del } + diff --git a/UI source code/dns_mapping_ui-master/src/api/tools/alipay.js b/UI source code/dns_mapping_ui-master/src/api/tools/alipay.js new file mode 100644 index 0000000..54090f5 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/tools/alipay.js @@ -0,0 +1,25 @@ +import request from '@/utils/request' + +export function get() { + return request({ + url: 'api/aliPay', + method: 'get' + }) +} + +export function update(data) { + return request({ + url: 'api/aliPay', + data, + method: 'put' + }) +} + +// 支付 +export function toAliPay(url, data) { + return request({ + url: 'api/' + url, + data, + method: 'post' + }) +} diff --git a/UI source code/dns_mapping_ui-master/src/api/tools/email.js b/UI source code/dns_mapping_ui-master/src/api/tools/email.js new file mode 100644 index 0000000..af030cb --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/tools/email.js @@ -0,0 +1,24 @@ +import request from '@/utils/request' + +export function get() { + return request({ + url: 'api/email', + method: 'get' + }) +} + +export function update(data) { + return request({ + url: 'api/email', + data, + method: 'put' + }) +} + +export function send(data) { + return request({ + url: 'api/email', + data, + method: 'post' + }) +} diff --git a/UI source code/dns_mapping_ui-master/src/api/tools/localStorage.js b/UI source code/dns_mapping_ui-master/src/api/tools/localStorage.js new file mode 100644 index 0000000..63ebe2b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/tools/localStorage.js @@ -0,0 +1,27 @@ +import request from '@/utils/request' + +export function add(data) { + return request({ + url: 'api/localStorage', + method: 'post', + data + }) +} + +export function del(ids) { + return request({ + url: 'api/localStorage/', + method: 'delete', + data: ids + }) +} + +export function edit(data) { + return request({ + url: 'api/localStorage', + method: 'put', + data + }) +} + +export default { add, edit, del } diff --git a/UI source code/dns_mapping_ui-master/src/api/tools/qiniu.js b/UI source code/dns_mapping_ui-master/src/api/tools/qiniu.js new file mode 100644 index 0000000..6d56771 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/api/tools/qiniu.js @@ -0,0 +1,40 @@ +import request from '@/utils/request' + +export function get() { + return request({ + url: 'api/qiNiuContent/config', + method: 'get' + }) +} + +export function update(data) { + return request({ + url: 'api/qiNiuContent/config', + data, + method: 'put' + }) +} + +export function download(id) { + return request({ + url: 'api/qiNiuContent/download/' + id, + method: 'get' + }) +} + +export function sync() { + return request({ + url: 'api/qiNiuContent/synchronize', + method: 'post' + }) +} + +export function del(ids) { + return request({ + url: 'api/qiNiuContent', + method: 'delete', + data: ids + }) +} + +export default { del, download, sync } diff --git a/UI source code/dns_mapping_ui-master/src/assets/401_images/401.gif b/UI source code/dns_mapping_ui-master/src/assets/401_images/401.gif Binary files differnew file mode 100644 index 0000000..cd6e0d9 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/401_images/401.gif diff --git a/UI source code/dns_mapping_ui-master/src/assets/404_images/404.png b/UI source code/dns_mapping_ui-master/src/assets/404_images/404.png Binary files differnew file mode 100644 index 0000000..3d8e230 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/404_images/404.png diff --git a/UI source code/dns_mapping_ui-master/src/assets/404_images/404_cloud.png b/UI source code/dns_mapping_ui-master/src/assets/404_images/404_cloud.png Binary files differnew file mode 100644 index 0000000..c6281d0 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/404_images/404_cloud.png diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/index.js b/UI source code/dns_mapping_ui-master/src/assets/icons/index.js new file mode 100644 index 0000000..2c6b309 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/index.js @@ -0,0 +1,9 @@ +import Vue from 'vue' +import SvgIcon from '@/components/SvgIcon'// svg component + +// register globally +Vue.component('svg-icon', SvgIcon) + +const req = require.context('./svg', false, /\.svg$/) +const requireAll = requireContext => requireContext.keys().map(requireContext) +requireAll(req) diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/Steve-Jobs.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/Steve-Jobs.svg new file mode 100644 index 0000000..53843e2 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/Steve-Jobs.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.586" height="200" class="icon" p-id="2886" t="1553488917000" version="1.1" viewBox="0 0 1027 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M512 750.933333c-112.64 0-211.626667-119.466667-245.76-242.346666-34.133333 0-61.44-44.373333-61.44-102.4 0-17.066667 3.413333-34.133333 6.826667-47.786667-3.413333-20.48-6.826667-47.786667-6.826667-68.266667C204.8 129.706667 341.333333 0 508.586667 0S819.2 133.12 819.2 290.133333c0 20.48-3.413333 47.786667-6.826667 68.266667 3.413333 13.653333 6.826667 30.72 6.826667 47.786667 0 58.026667-27.306667 102.4-61.44 102.4-34.133333 122.88-133.12 242.346667-245.76 242.346666z m-235.52-279.893333h6.826667c3.413333 3.413333 10.24 6.826667 10.24 10.24 30.72 129.706667 129.706667 235.52 218.453333 235.52s187.733333-105.813333 218.453333-235.52c0-6.826667 6.826667-10.24 10.24-10.24 3.413333-3.413333 10.24 0 17.066667 0h3.413333c10.24 0 27.306667-27.306667 27.306667-68.266667 0-13.653333-3.413333-30.72-6.826667-40.96v-10.24c0-13.653333 3.413333-40.96 3.413334-61.44C785.066667 150.186667 658.773333 34.133333 508.586667 34.133333 358.4 34.133333 238.933333 150.186667 238.933333 290.133333c0 20.48 3.413333 47.786667 6.826667 64.853334v10.24c-3.413333 10.24-6.826667 23.893333-6.826667 40.96 0 40.96 17.066667 68.266667 27.306667 68.266666h3.413333c0-3.413333 3.413333-3.413333 6.826667-3.413333z" p-id="2887"/><path fill="#bfbfbf" d="M1006.933333 1024H17.066667c-10.24 0-17.066667-6.826667-17.066667-17.066667v-40.96c0-116.053333 75.093333-218.453333 184.32-259.413333l112.64-30.72c6.826667 0 13.653333 0 17.066667 3.413333 51.2 58.026667 122.88 136.533333 197.973333 136.533334s143.36-78.506667 197.973333-136.533334c3.413333-3.413333 10.24-6.826667 17.066667-3.413333l109.226667 30.72c112.64 37.546667 191.146667 150.186667 191.146666 266.24v30.72c-3.413333 13.653333-10.24 20.48-20.48 20.48zM34.133333 989.866667h955.733334v-13.653334c0-98.986667-71.68-201.386667-167.253334-235.52l-98.986666-27.306666c-54.613333 61.44-129.706667 139.946667-215.04 139.946666s-160.426667-78.506667-215.04-139.946666l-98.986667 27.306666c-95.573333 34.133333-160.426667 122.88-160.426667 225.28v23.893334zM785.066667 375.466667h-51.2c-6.826667 0-13.653333-6.826667-17.066667-13.653334 0-3.413333-23.893333-109.226667-30.72-184.32-3.413333-30.72-30.72-58.026667-61.44-58.026666-23.893333 0-40.96 13.653333-58.026667 30.72-17.066667 13.653333-34.133333 20.48-54.613333 20.48-27.306667 0-47.786667 0-64.853333-20.48s-34.133333-30.72-47.786667-30.72c-40.96 0-71.68 30.72-75.093333 68.266666l-17.066667 170.666667c0 3.413333-3.413333 10.24-6.826667 10.24s-6.826667 6.826667-13.653333 6.826667c0 0-23.893333-3.413333-51.2-3.413334-10.24 0-17.066667-6.826667-17.066667-17.066666s10.24-17.066667 20.48-17.066667c13.653333 0 27.306667 0 37.546667 3.413333l17.066667-153.6c3.413333-58.026667 54.613333-102.4 109.226666-102.4 27.306667 0 54.613333 23.893333 71.68 44.373334 6.826667 6.826667 17.066667 6.826667 37.546667 6.826666 10.24 0 20.48-3.413333 30.72-13.653333 20.48-17.066667 47.786667-37.546667 81.92-37.546667 51.2 0 92.16 37.546667 95.573333 88.746667 3.413333 58.026667 20.48 136.533333 27.306667 167.253333H785.066667c10.24 0 17.066667 6.826667 17.066666 17.066667s-6.826667 17.066667-17.066666 17.066667z" p-id="2888"/><path fill="#bfbfbf" d="M324.266667 426.666667c-3.413333 0-10.24 0-13.653334-3.413334l-51.2-51.2c-6.826667-6.826667-6.826667-17.066667 0-23.893333s17.066667-6.826667 23.893334 0l51.2 51.2c6.826667 6.826667 6.826667 17.066667 0 23.893333 0 3.413333-6.826667 3.413333-10.24 3.413334zM699.733333 426.666667c-3.413333 0-6.826667 0-10.24-3.413334-6.826667-6.826667-10.24-17.066667-3.413333-23.893333l34.133333-51.2c6.826667-6.826667 17.066667-10.24 23.893334-3.413333s10.24 17.066667 3.413333 23.893333l-34.133333 51.2c-3.413333 3.413333-6.826667 6.826667-13.653334 6.826667zM563.2 426.666667c-3.413333 0-6.826667 0-10.24-3.413334 0 0-20.48-13.653333-40.96-13.653333s-40.96 13.653333-40.96 13.653333c-6.826667 6.826667-17.066667 3.413333-23.893333-3.413333-6.826667-6.826667-3.413333-17.066667 3.413333-23.893333 0 0 27.306667-20.48 61.44-20.48s61.44 20.48 61.44 20.48c6.826667 6.826667 10.24 17.066667 3.413333 23.893333-3.413333 3.413333-6.826667 6.826667-13.653333 6.826667zM631.466667 614.4c-27.306667 0-51.2-20.48-71.68-37.546667-17.066667-17.066667-34.133333-30.72-54.613334-30.72-17.066667 0-30.72 13.653333-47.786666 30.72-17.066667 17.066667-37.546667 37.546667-68.266667 37.546667-44.373333 0-58.026667-13.653333-81.92-37.546667l-17.066667-17.066666c-6.826667-6.826667-6.826667-17.066667 0-23.893334s17.066667-6.826667 23.893334 0l17.066666 17.066667c23.893333 23.893333 27.306667 27.306667 54.613334 27.306667 13.653333 0 27.306667-13.653333 44.373333-27.306667 20.48-20.48 40.96-40.96 71.68-40.96 30.72 0 54.613333 20.48 75.093333 40.96 17.066667 13.653333 34.133333 27.306667 47.786667 27.306667 30.72 0 34.133333-3.413333 54.613333-27.306667 3.413333-6.826667 10.24-10.24 17.066667-17.066667s17.066667-6.826667 23.893333 0 6.826667 17.066667 0 23.893334c-6.826667 6.826667-10.24 13.653333-17.066666 17.066666-13.653333 23.893333-27.306667 37.546667-71.68 37.546667zM529.066667 648.533333h-34.133334c-10.24 0-17.066667-6.826667-17.066666-17.066666s6.826667-17.066667 17.066666-17.066667h34.133334c10.24 0 17.066667 6.826667 17.066666 17.066667s-6.826667 17.066667-17.066666 17.066666z" p-id="2889"/><path fill="#bfbfbf" d="M631.466667 512c-47.786667 0-85.333333-37.546667-85.333334-85.333333s37.546667-85.333333 85.333334-85.333334 85.333333 37.546667 85.333333 85.333334-37.546667 85.333333-85.333333 85.333333z m0-136.533333c-27.306667 0-51.2 23.893333-51.2 51.2s23.893333 51.2 51.2 51.2 51.2-23.893333 51.2-51.2-23.893333-51.2-51.2-51.2zM392.533333 512C344.746667 512 307.2 474.453333 307.2 426.666667s37.546667-85.333333 85.333333-85.333334 85.333333 37.546667 85.333334 85.333334-37.546667 85.333333-85.333334 85.333333z m0-136.533333c-27.306667 0-51.2 23.893333-51.2 51.2s23.893333 51.2 51.2 51.2 51.2-23.893333 51.2-51.2-23.893333-51.2-51.2-51.2z" p-id="2890"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/alipay.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/alipay.svg new file mode 100644 index 0000000..9138981 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/alipay.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="1468" t="1546239206365" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path d="M907 378.05l-12.4-14.33c-61-70.41-166.93-177.81-236.2-239.4l-14.12-12.58C609.07 80.37 562.07 63.09 512 63.09s-97.08 17.28-132.32 48.65l-14.12 12.57c-69.28 61.61-175.24 169-236.2 239.41l-12.41 14.33c-63.92 73.87-63.92 194 0 267.87l12.41 14.33C190.24 730.6 296.2 838 365.54 899.69l14.14 12.57c35.24 31.37 82.23 48.65 132.32 48.65s97.06-17.28 132.32-48.65l14.13-12.57 8.15-7.25c21.93-19.46 31.93-28.35 62.69-58.93l7.27-7.36-1.16-1.22a28.35 28.35 0 0 0-45.87-32.14c-2.92 2.78-43.63 41.53-68.73 63.91l-14.1 12.56c-24.89 22.1-58.53 34.28-94.7 34.28s-69.82-12.19-94.69-34.31l-14.14-12.58c-67.85-60.34-171.47-165.38-231-234.14l-12.4-14.32c-21.73-25.12-33.7-59.29-33.7-96.2s12-71.07 33.7-96.17l12.41-14.33c59.5-68.75 163.12-173.79 231-234.15l14.1-12.57c24.86-22.12 58.49-34.31 94.68-34.31s69.83 12.19 94.7 34.3l14.12 12.58c67.86 60.37 171.49 165.41 231 234.14l12.39 14.34c45.22 52.21 45.34 143.76 0.26 192.07l-7.15 7.69c-20.35 21.94-32.64 35.19-45.62 39.1-12.3 3.71-27.89-0.23-57.53-14.54-49.55-23.94-119.64-64-144-78 9.87-19.61 32.46-67.6 43.11-115.62l2.86-12.87H534.5v-15.06h154.78v-57.37H534.5v-72.41h-56.89v72.41H322.83v57.37h154.78v15.05H358.54V491H573c-4.63 14.52-13.16 32.57-19.19 44.37-22.13-8.73-80.75-29.33-141-29.33-37.94 0-69.92 10.28-92.49 29.71-22.37 19.27-34.19 46-34.19 77.42s11.32 58.29 32.75 77.74c21.9 19.89 53 30.41 90 30.41 42.76 0 87.09-19 128.18-54.78a326.76 326.76 0 0 0 43.61-46.35c22.9 12.75 90 50 152.61 83.47 40.83 21.85 69.5 26.18 95.87 14.47 25.09-11.14 47.07-36.53 77.49-71.68l0.47-0.54C971 572.07 971 451.9 907 378.05zM407.83 662c-60.15 0-64.83-37.38-64.83-48.82a48.21 48.21 0 0 1 12.15-31.36c11.06-12.2 28.45-18.39 51.69-18.39 50 0 95 17.21 115.39 26.35C503.71 611.69 456 662 407.83 662z" p-id="1469"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/anq.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/anq.svg new file mode 100644 index 0000000..a466608 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/anq.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="6244" t="1553935360914" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#8a8a8a" d="M957.217391 86.372174C957.217391 86.372174 957.217391 608.211478 957.217391 608.211478 957.217391 639.510261 949.782261 670.630957 934.956522 701.573565 920.086261 732.605217 900.674783 762.568348 876.633043 791.685565 852.591304 820.758261 825.121391 848.317217 794.267826 874.273391 763.369739 900.274087 732.070957 923.425391 700.326957 943.727304 668.538435 964.073739 637.68487 980.992 607.721739 994.437565 577.758609 1007.88313 551.490783 1017.09913 528.918261 1022.130087 528.918261 1022.130087 518.233043 1024 518.233043 1024 518.233043 1024 508.438261 1022.130087 508.438261 1022.130087 485.286957 1017.09913 458.440348 1007.88313 427.853913 994.437565 397.267478 980.992 365.523478 964.073739 332.577391 943.727304 299.631304 923.425391 267.308522 900.274087 235.52 874.273391 203.776 848.317217 175.415652 820.758261 150.483478 791.685565 125.551304 762.568348 105.382957 732.605217 89.978435 701.573565 74.48487 670.630957 66.782609 639.510261 66.782609 608.211478 66.782609 608.211478 66.782609 86.372174 66.782609 86.372174 66.782609 86.372174 103.290435 80.717913 103.290435 80.717913 103.290435 80.717913 512.890435 0 512.890435 0 512.890435 0 930.504348 80.717913 930.504348 80.717913 930.504348 80.717913 957.217391 86.372174 957.217391 86.372174 957.217391 86.372174 957.217391 86.372174 957.217391 86.372174ZM513.024 75.553391C513.024 75.553391 508.082087 74.529391 508.082087 74.529391 508.082087 74.529391 156.538435 137.527652 156.538435 137.527652 156.538435 137.527652 156.538435 466.765913 156.538435 466.765913 156.538435 466.765913 513.024 466.765913 513.024 466.765913 513.024 466.765913 513.024 75.553391 513.024 75.553391 513.024 75.553391 513.024 75.553391 513.024 75.553391ZM867.461565 466.765913C867.461565 466.765913 513.024 466.765913 513.024 466.765913 513.024 466.765913 513.024 935.401739 513.024 935.401739 535.81913 929.881043 560.617739 921.466435 587.419826 910.113391 614.177391 898.760348 640.623304 885.359304 666.713043 869.865739 692.847304 854.372174 717.957565 837.186783 742.13287 818.265043 766.308174 799.343304 787.634087 778.99687 806.288696 757.314783 824.898783 735.677217 839.724522 713.149217 850.810435 689.730783 861.94087 666.35687 867.461565 642.582261 867.461565 618.496 867.461565 618.496 867.461565 466.765913 867.461565 466.765913 867.461565 466.765913 867.461565 466.765913 867.461565 466.765913Z" p-id="6245"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/app.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/app.svg new file mode 100644 index 0000000..0796da3 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/app.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1574649142168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1910" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M468.693333 16.725333a85.333333 85.333333 0 0 1 82.56 0l381.952 211.072a85.333333 85.333333 0 0 1 44.074667 74.666667v419.029333a85.333333 85.333333 0 0 1-44.074667 74.666667l-381.952 211.114667a85.333333 85.333333 0 0 1-82.56 0l-381.952-211.072A85.333333 85.333333 0 0 1 42.666667 721.493333V302.506667a85.333333 85.333333 0 0 1 44.074666-74.666667L468.693333 16.682667z m423.253334 285.781334l-381.994667-211.072L128 302.506667v418.986666l381.952 211.072 381.994667-211.072V302.506667z m-684.714667 42.197333a42.666667 42.666667 0 0 1 57.984-16.725333l244.736 135.253333 244.778667-135.253333a42.666667 42.666667 0 0 1 41.258666 74.666666l-243.370666 134.528v268.16a42.666667 42.666667 0 0 1-85.333334 0V537.173333L223.914667 402.688a42.666667 42.666667 0 0 1-16.682667-58.026667z" fill="#bfbfbf" p-id="1911"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/backup.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/backup.svg new file mode 100644 index 0000000..a3272a4 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/backup.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1574649191790" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2774" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M646 1024H100A100 100 0 0 1 0 924V258a100 100 0 0 1 100-100h546a100 100 0 0 1 100 100v31a40 40 0 1 1-80 0v-31a20 20 0 0 0-20-20H100a20 20 0 0 0-20 20v666a20 20 0 0 0 20 20h546a20 20 0 0 0 20-20V713a40 40 0 0 1 80 0v211a100 100 0 0 1-100 100z" fill="#cdcdcd" p-id="2775"></path><path d="M924 866H806a40 40 0 0 1 0-80h118a20 20 0 0 0 20-20V100a20 20 0 0 0-20-20H378a20 20 0 0 0-20 20v8a40 40 0 0 1-80 0v-8A100 100 0 0 1 378 0h546a100 100 0 0 1 100 100v666a100 100 0 0 1-100 100z" fill="#cdcdcd" p-id="2776"></path><path d="M469 887a40 40 0 0 1-27-10L152 618a40 40 0 0 1 1-60l290-248a40 40 0 0 1 66 30v128a367 367 0 0 0 241-128l94-111a40 40 0 0 1 70 35l-26 109a430 430 0 0 1-379 332v142a40 40 0 0 1-40 40zM240 589l189 169v-91a40 40 0 0 1 40-40c144 0 269-85 323-214a447 447 0 0 1-323 137 40 40 0 0 1-40-40v-83z" fill="#cdcdcd" p-id="2777"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/blog.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/blog.svg new file mode 100644 index 0000000..a990eba --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/blog.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1649727231933" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14212" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M957.2 445.4c-3.6-16-13.6-30.8-25-37-3.6-2-26-4.4-50-5.4-40.2-1.8-44.6-2.6-57.4-10-20.2-11.8-25.6-24.6-25.8-59-0.2-66-27.6-127.4-81.8-182.6-38.6-39.4-81.8-66-131-81-11.8-3.6-38.2-4.8-126.6-5.8-138.8-1.6-169.6 1.2-216.8 20C155.8 119 93.4 192.2 70.6 285.8 66.4 303.4 65.4 331.6 64.4 493.6c-1.2 203 0.2 232.8 12.8 273 31.2 99.2 119.8 172.6 208.8 188.6 29.6 5.4 394.6 6.6 432 1.6 65-8.8 116-35 163.8-83.8 34.6-35.4 56.2-73.6 70.4-124.2 9.8-35.2 9-285.6 5-303.4z m-644.2-127.2c15.6-15.8 20-16.4 117.6-16.4 87.8 0 90.8 0.2 103.6 6.8 18.6 9.4 26.8 22.6 26.8 43.8 0 19-7.6 32.4-24.6 43.2-9.2 5.8-14.6 6.2-100.6 6.6-53 0.4-95.4-0.8-101.6-2.4-33.2-9.4-45.6-57-21.2-81.6z m383.6 399.6l-29.8 4.8-155 1.8c-136.2 1.6-174.6-0.8-181.8-4-14.2-6.2-27.6-23.4-29.8-38.8-2.2-14.6 5.2-34.6 16.4-44.8 14.2-12.8 20.4-13.2 194.6-13.4 179.2-0.2 178.2-0.2 195.2 15.6 24.2 22.6 19 62.4-9.8 78.8z" p-id="14213" fill="#bfbfbf"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/chain.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/chain.svg new file mode 100644 index 0000000..ed3317f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/chain.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="654" t="1545959978831" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path d="M877.297288 553.796942L553.79643 877.298823c-54.370305 54.369282-126.656655 84.311221-203.547883 84.312245-76.890204-0.001023-149.177578-29.942963-203.546859-84.312245S62.389444 750.641145 62.389444 673.750941c0-76.890204 29.942963-149.177578 84.312244-203.547883l135.442762-135.441738c75.829036-75.829036 199.213157-75.829036 275.043217 0s75.830059 199.214181 0 275.043217L399.320173 767.674077c-17.620309 17.620309-46.188972 17.620309-63.809281 0-17.620309-17.621333-17.620309-46.188972 0-63.809281l157.867493-157.867494c40.645722-40.645722 40.645722-106.779955 0-147.424654-40.644699-40.645722-106.778932-40.645722-147.424654 0L210.51097 534.01234c-77.051887 77.05291-77.051887 202.423269 0 279.476179 77.051887 77.051887 202.423269 77.051887 279.475155 0l323.501882-323.501882c77.051887-77.050864 77.051887-202.423269 0-279.475156-77.05291-77.051887-202.424292-77.050864-279.476179 0-17.619286 17.620309-46.188972 17.620309-63.809281 0s-17.619286-46.189995 0-63.809281c54.369282-54.369282 126.657678-84.313268 203.546859-84.312244 76.892251 0 149.178601 29.942963 203.548906 84.312244 54.369282 54.369282 84.311221 126.656655 84.311221 203.547882 0 76.889181-29.942963 149.176554-84.312245 203.54686z" p-id="655"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/chart.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/chart.svg new file mode 100644 index 0000000..27728fb --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/chart.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h36.571V128H0V54.857zM91.429 27.43H128V128H91.429V27.429zM45.714 0h36.572v128H45.714V0z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/codeConsole.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/codeConsole.svg new file mode 100644 index 0000000..672ec6e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/codeConsole.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="6717" t="1547360688278" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M890 120H134a70 70 0 0 0-70 70v500a70 70 0 0 0 70 70h756a70 70 0 0 0 70-70V190a70 70 0 0 0-70-70z m-10 520a40 40 0 0 1-40 40H712V448a40 40 0 0 0-80 0v232h-80V368a40 40 0 0 0-80 0v312h-80V512a40 40 0 0 0-80 0v168H184a40 40 0 0 1-40-40V240a40 40 0 0 1 40-40h656a40 40 0 0 1 40 40zM696 824H328a40 40 0 0 0 0 80h368a40 40 0 0 0 0-80z" p-id="6718"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dashboard.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dashboard.svg new file mode 100644 index 0000000..5317d37 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dashboard.svg @@ -0,0 +1 @@ +<svg width="128" height="100" xmlns="http://www.w3.org/2000/svg"><path d="M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/database.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/database.svg new file mode 100644 index 0000000..7fbad9b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/database.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1574649229600" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3752" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M942 191.9C939.8 128.9 748.1 78 512 78S84.2 128.9 82 191.9V831c0 63.5 192.5 115 430 115s430-51.5 430-115V191.9z m-56.7 393.8c-4.6 3.3-11.6 7.4-21.9 12.2-21.3 9.8-50.5 19.1-84.4 26.8-74 16.8-168.8 26-267 26s-193-9.2-267-26c-33.9-7.7-63.1-16.9-84.4-26.8-10.3-4.8-17.3-8.9-21.9-12.2 0.1-0.1 0.2-0.1 0.3-0.2h-7v-123c72.2 36.4 215.3 61.1 380 61.1s307.8-24.8 380-61.1v122.9h-7l0.3 0.3z m0-177c-4.6 3.3-11.6 7.4-21.9 12.2-21.3 9.8-50.5 19.1-84.4 26.8-74 16.8-168.8 26-267 26s-193-9.2-267-26c-33.9-7.7-63.1-16.9-84.4-26.8-10.3-4.8-17.3-8.9-21.9-12.2 0.1-0.1 0.2-0.1 0.3-0.2h-7V246.9c72.2 36.4 215.3 61.1 380 61.1s307.8-24.8 380-61.1v161.6h-7c0.1 0 0.2 0.1 0.3 0.2zM160.7 180.8C182 171 211.2 161.7 245 154c74-16.8 168.8-26 267-26s193 9.2 267 26c33.9 7.7 63.1 16.9 84.4 26.8 10.3 4.8 17.3 8.9 21.9 12.2-4.6 3.3-11.6 7.4-21.9 12.2C842 215 812.8 224.3 779 232c-74 16.8-168.8 26-267 26s-193-9.2-267-26c-33.9-7.7-63.1-16.9-84.4-26.8-10.3-4.8-17.3-8.9-21.9-12.2 4.7-3.3 11.7-7.4 22-12.2zM885.3 831c-4.6 3.3-11.6 7.4-21.9 12.2C842 853 812.8 862.3 779 870c-74 16.8-168.8 26-267 26s-193-9.2-267-26c-33.9-7.7-63.1-16.9-84.4-26.8-10.3-4.8-17.3-8.9-21.9-12.2 0.1-0.1 0.2-0.1 0.3-0.2h-7V639.5c72.2 36.4 215.3 61.1 380 61.1s307.8-24.8 380-61.1v191.3h-7c0.1 0.1 0.2 0.1 0.3 0.2z" fill="#cdcdcd" p-id="3753"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/date.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/date.svg new file mode 100644 index 0000000..0540e99 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/date.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="5330" t="1553935012815" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#8a8a8a" d="M453.22752 781.67168 170.31936 781.67168 170.31936 409.18016l650.45632 0c11.6864 0 21.15968-9.47328 21.15968-21.15968L841.93536 218.68032l0-12.3904c0-11.6864-9.47328-21.15968-21.15968-21.15968l-11.8784 0L660.94464 185.13024l0-35.97184c0-11.6864-9.47328-21.15968-21.15968-21.15968-11.68768 0-21.15968 9.47328-21.15968 21.15968l0 35.97184L356.24704 185.13024l0-35.97184c0-11.6864-9.47328-21.15968-21.15968-21.15968s-21.15968 9.47328-21.15968 21.15968l0 35.97184L161.04064 185.13024l-11.88096 0c-11.6864 0-21.15968 9.47328-21.15968 21.15968l0 12.3904 0 169.34144 0 402.4192c0 18.49984 14.8224 33.55008 33.04064 33.55008l292.18816 0c11.6864 0 21.15968-9.472 21.15968-21.15968C474.38848 791.14496 464.91392 781.67168 453.22752 781.67168zM170.31936 227.4496l143.60832 0 0 35.97184c0 11.6864 9.47328 21.15968 21.15968 21.15968s21.15968-9.472 21.15968-21.15968l0-35.97184 262.37696 0 0 35.97184c0 11.6864 9.472 21.15968 21.15968 21.15968 11.6864 0 21.15968-9.472 21.15968-21.15968l0-35.97184L799.616 227.4496l0 139.41248L170.31936 366.86208 170.31936 227.4496zM690.49984 483.10016c-113.83808 0-206.44992 92.61312-206.44992 206.45248 0 113.83552 92.61184 206.44736 206.44992 206.44736s206.44992-92.61312 206.44992-206.44736C896.94976 575.71328 804.33792 483.10016 690.49984 483.10016zM690.49984 853.68064c-90.50112 0-164.13056-73.62816-164.13056-164.13184s73.62816-164.13184 164.13056-164.13184c90.5024 0 164.13184 73.62816 164.13184 164.13184S781.00224 853.68064 690.49984 853.68064zM390.10304 640.81536l-143.8848 0c-11.68768 0-21.15968 9.472-21.15968 21.15968 0 11.68512 9.472 21.1584 21.15968 21.1584l143.8848 0c11.6864 0 21.15968-9.47328 21.15968-21.1584C411.26144 650.28736 401.78816 640.81536 390.10304 640.81536zM390.10304 521.32608l-143.8848 0c-11.68768 0-21.15968 9.47328-21.15968 21.1584 0 11.68768 9.472 21.15968 21.15968 21.15968l143.8848 0c11.6864 0 21.15968-9.472 21.15968-21.15968C411.26144 530.80064 401.78816 521.32608 390.10304 521.32608zM803.1744 668.39296l-91.51488 0 0-50.78272c0-11.68768-9.472-21.15968-21.1584-21.15968s-21.15968 9.472-21.15968 21.15968l0 71.9424c0 11.68512 9.47328 21.1584 21.15968 21.1584l112.67328 0c11.6864 0 21.15968-9.47328 21.15968-21.1584C824.33536 677.86496 814.8608 668.39296 803.1744 668.39296z" p-id="5331"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/deploy.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/deploy.svg new file mode 100644 index 0000000..f4a1c56 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/deploy.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1574649300337" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4312" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M877.952 447.616v-0.256a272 272 0 0 0-479.68-175.68 166.144 166.144 0 0 0-226.016 155.296c0 4.768 0.32 9.6 0.704 14.144A196.896 196.896 0 0 0 206.592 832H448v-256H304l208-208 208 208H576v256h241.408a196.96 196.96 0 0 0 60.544-384.384z" fill="#cdcdcd" p-id="4313"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dept.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dept.svg new file mode 100644 index 0000000..894e4bf --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dept.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="1799" t="1553478255619" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M329.285097 317.714062l-8.422833 4.428869c-8.78099 4.584412-13.528108 14.84715-11.923564 24.415063 1.644453 4.909823 3.491521 9.864672 5.492084 14.747889 2.030239 4.854565 4.230348 9.652847 6.53688 14.293541 5.621021 7.891737 16.246009 11.824303 25.699312 8.858762l9.041934-2.868327c14.741749-3.860934 31.115672-0.056282 42.62582 11.512195 11.549034 11.526521 15.374152 27.863604 11.549034 42.570561l-2.882654 9.126868c-2.958378 9.438976 0.938372 20.042475 8.830109 25.706475 4.634554 2.328022 9.403161 4.52813 14.323217 6.529717 4.876054 2.043542 9.80839 3.846608 14.739702 5.478781 9.538237 1.603521 19.87363-3.123131 24.414039-11.910261l4.402263-8.388041c7.67889-13.144368 21.915126-22.002107 38.267559-22.002107 16.338107 0 30.547737 8.829086 38.255279 21.931498l4.41352 8.459672c4.584412 8.78713 14.84715 13.513782 24.414039 11.910261 4.91187-1.632173 9.851369-3.462868 14.734586-5.478781 4.882194-2.030239 9.66615-4.201695 14.322194-6.529717 7.891737-5.622044 11.809977-16.253172 8.843412-25.706475l-2.852978-9.041934c-3.859911-14.733563-0.069585-31.085996 11.484565-42.655496 11.55415-11.525498 27.878954-15.372106 42.599214-11.512195l9.097192 2.88163c9.426697 2.952238 20.044522-0.937348 25.693172-8.829086 2.313695-4.656043 4.527107-9.411347 6.54302-14.322194 2.029216-4.883217 3.847631-9.80839 5.495154-14.748912 1.616824-9.581216-3.108804-19.843954-11.911284-24.429389l-8.402367-4.400217c-13.132088-7.665587-21.98778-21.901823-21.98778-38.255279 0-16.32378 8.830109-30.589692 21.974477-38.268582l8.416693-4.443196c8.80248-4.571109 13.528108-14.832823 11.924587-24.400736-1.6465-4.910846-3.479241-9.850345-5.493108-14.733563-2.031263-4.868891-4.202719-9.680477-6.529717-14.308891-5.622044-7.890714-16.253172-11.82328-25.708522-8.842389l-9.05626 2.852978c-14.747889 3.861958-31.071669 0.057305-42.654472-11.512195-11.55415-11.55415-15.344476-27.877931-11.484565-42.612517l2.852978-9.05626c2.966565-9.44-0.951675-20.043499-8.856715-25.692149-4.641717-2.328022-9.397021-4.542456-14.307867-6.544043-4.883217-2.029216-9.82374-3.846608-14.734586-5.465478-9.567913-1.632173-19.872606 3.123131-24.414039 11.895935l-4.400217 8.389064c-7.67889 13.174044-21.931498 22.002107-38.268582 22.002107-16.309454 0-30.576389-8.828063-38.267559-22.002107l-4.387937-8.389064c-4.554736-8.771781-14.8318-13.528108-24.405853-11.895935-4.954849 1.604544-9.873882 3.435239-14.763239 5.4225-4.883217 2.044566-9.688663 4.217045-14.323217 6.545066-7.891737 5.649674-11.808954 16.266475-8.830109 25.735128l2.826372 9.05626c3.882424 14.762215 0.057305 31.085996-11.491729 42.612517-11.510148 11.5695-27.849278 15.373129-42.611493 11.526521l-9.070586-2.867304c-9.44-2.980891-20.063965 0.951675-25.686009 8.842389-2.342348 4.628414-4.52813 9.44-6.53688 14.308891-2.036379 4.882194-3.847631 9.822716-5.492084 14.733563-1.603521 9.581216 3.142573 19.85828 11.923564 24.443715l8.402367 4.400217c13.156648 7.67889 21.986757 21.944801 21.986757 38.268582C351.251388 295.79689 342.421278 310.019823 329.285097 317.714062zM511.977999 171.706687c59.532885 0 107.795075 48.275493 107.795075 107.779725 0 59.490929-48.26219 107.752096-107.795075 107.752096-59.533908 0-107.752096-48.26219-107.752096-107.752096C404.226926 219.98218 452.445114 171.706687 511.977999 171.706687z" p-id="1800"/><path fill="#bfbfbf" d="M924.647713 689.174212 798.570249 689.174212 798.570249 581.650313c0-26.387997-21.476127-47.850821-47.864124-47.850821L276.2543 533.799492c-26.386974 0-47.851844 21.462824-47.851844 47.850821l0 107.523899L99.345124 689.174212c-20.419052 0-36.95568 16.550954-36.95568 36.948517l0 184.771237c0 20.399609 16.536628 36.962843 36.95568 36.962843l273.965675 0c20.397562 0 36.947494-16.564257 36.947494-36.962843L410.258293 726.122729c0-20.398586-16.550954-36.948517-36.947494-36.948517l-123.103736 0L250.207064 581.650313c0-14.366196 11.68104-26.047236 26.047236-26.047236l474.451826 0c14.364149 0 26.062586 11.68104 26.062586 26.047236l0 107.523899L650.689201 689.174212c-20.412912 0-36.962843 16.550954-36.962843 36.948517l0 184.771237c0 20.399609 16.549931 36.962843 36.962843 36.962843l273.958512 0c20.397562 0 36.96182-16.564257 36.96182-36.962843L961.609533 726.122729C961.609533 705.725166 945.044252 689.174212 924.647713 689.174212z" p-id="1801"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dev.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dev.svg new file mode 100644 index 0000000..ed4d23c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dev.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1546567861908" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2422" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M318.577778 819.2L17.066667 512l301.511111-307.2 45.511111 45.511111L96.711111 512l267.377778 261.688889zM705.422222 819.2l-45.511111-45.511111L927.288889 512l-267.377778-261.688889 45.511111-45.511111L1006.933333 512zM540.785778 221.866667l55.751111 11.150222L483.157333 802.133333l-55.751111-11.093333z" fill="#bfbfbf" p-id="2423"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/develop.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/develop.svg new file mode 100644 index 0000000..e189223 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/develop.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="2807" t="1547195013953" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#cdcdcd" d="M529.0496 527.616l-30.7712-30.7456 85.0688-85.0944 30.7712 30.7712z" p-id="2808"/><path fill="#cdcdcd" d="M0 340.48l427.52 256 248.32 427.52L1024 0l-1024 340.48zM665.6 921.6l-207.36-355.84-355.84-212.48L911.36 81.92l-243.2 243.2 30.72 30.72 243.2-243.2L665.6 921.6z" p-id="2809"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dictionary.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dictionary.svg new file mode 100644 index 0000000..6e83c43 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/dictionary.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="1497" t="1554868028575" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M558.409143 658.285714h-92.818286l-28.379428 62.427429a18.285714 18.285714 0 1 1-33.28-15.140572l91.428571-201.142857a18.285714 18.285714 0 0 1 33.28 0l91.428571 201.142857a18.285714 18.285714 0 1 1-33.28 15.140572L558.409143 658.285714z m-16.64-36.571428L512 556.178286 482.230857 621.714286h59.538286zM329.142857 128h475.428572a18.285714 18.285714 0 1 1 0 36.571429H329.142857a91.428571 91.428571 0 0 0 0 182.857142h475.428572a18.285714 18.285714 0 0 1 18.285714 18.285715v512a18.285714 18.285714 0 0 1-18.285714 18.285714H329.142857A128 128 0 0 1 201.142857 768V256A128 128 0 0 1 329.142857 128zM237.714286 345.6V768A91.428571 91.428571 0 0 0 329.142857 859.428571h457.142857v-475.428571H329.142857a127.634286 127.634286 0 0 1-91.428571-38.4zM329.142857 274.285714a18.285714 18.285714 0 0 1 0-36.571428h438.857143a18.285714 18.285714 0 1 1 0 36.571428H329.142857z" p-id="1498"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/doc.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/doc.svg new file mode 100644 index 0000000..9160de8 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/doc.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1583752001956" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9290" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M891.8 320H608V39.2L891.8 320zM704 384v260c0 133.6-73 200.2-226.6 200.2H288V169.6h189.4c24 0 46.2 1.6 66.2 5v-168C521.8 2.2 498.8 0 474.4 0H96v1024h378.4C755.4 1024 896 894.8 896 636.2V384h-192z" fill="#707070" p-id="9291"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/download.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/download.svg new file mode 100644 index 0000000..0243c6a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/download.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1583752303941" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16654" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M1024 896v128H0v-320h128v192h768v-192h128v192zM576 554.688L810.688 320 896 405.312l-384 384-384-384L213.312 320 448 554.688V0h128v554.688z" fill="#707070" p-id="16655"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/edit.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/edit.svg new file mode 100644 index 0000000..d26101f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/edit.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M106.133 67.2a4.797 4.797 0 0 0-4.8 4.8c0 .187.014.36.027.533h-.027V118.4H9.6V26.667h50.133c2.654 0 4.8-2.147 4.8-4.8 0-2.654-2.146-4.8-4.8-4.8H9.6a9.594 9.594 0 0 0-9.6 9.6V118.4c0 5.307 4.293 9.6 9.6 9.6h91.733c5.307 0 9.6-4.293 9.6-9.6V72.533h-.026c.013-.173.026-.346.026-.533 0-2.653-2.146-4.8-4.8-4.8z"/><path d="M125.16 13.373L114.587 2.8c-3.747-3.747-9.854-3.72-13.6.027l-52.96 52.96a4.264 4.264 0 0 0-.907 1.36L33.813 88.533c-.746 1.76-.226 3.534.907 4.68 1.133 1.147 2.92 1.667 4.693.92l31.4-13.293c.507-.213.96-.52 1.36-.907l52.96-52.96c3.747-3.746 3.774-9.853.027-13.6zM66.107 72.4l-18.32 7.76 7.76-18.32L92.72 24.667l10.56 10.56L66.107 72.4zm52.226-52.227l-8.266 8.267-10.56-10.56 8.266-8.267.027-.026 10.56 10.56-.027.026z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/education.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/education.svg new file mode 100644 index 0000000..7bfb01d --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/education.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M88.883 119.565c-7.284 0-19.434 2.495-21.333 8.25v.127c-4.232.13-5.222 0-7.108 0-1.895-5.76-14.045-8.256-21.333-8.256H0V0h42.523c9.179 0 17.109 5.47 21.47 13.551C68.352 5.475 76.295 0 85.478 0H128v119.57l-39.113-.005h-.004zM60.442 24.763c0-9.651-8.978-16.507-17.777-16.507H7.108V111.43H39.11c7.054-.14 18.177.082 21.333 6.12v-4.628c-.134-5.722-.004-13.522 0-13.832V27.413l.004-2.655-.004.005zm60.442-16.517h-35.55c-8.802 0-17.78 6.856-17.78 16.493v74.259c.004.32.138 8.115 0 13.813v4.627c3.155-6.022 14.279-6.26 21.333-6.114h32V8.25l-.003-.005z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/email.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/email.svg new file mode 100644 index 0000000..f1cf3ae --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/email.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="2851" t="1554009929581" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#8a8a8a" d="M511.471952 957.559056c-51.013955 0-93.475781-37.318473-101.502932-86.07185l-199.795618 0c-32.961053 0-59.794291-26.834261-59.794291-59.827038 0-12.417319 3.735224-24.277935 10.811684-34.336434l83.646513-111.561431 533.235518 0 83.515524 111.364948c7.306713 10.484212 11.008167 22.246587 11.008167 34.532917 0 32.9938-26.833238 59.827038-59.794291 59.827038l-199.861112 0C604.914986 920.241606 562.485907 957.559056 511.471952 957.559056zM261.61307 699.312805l-73.293289 97.734961c-2.751786 3.964455-4.390168 9.174325-4.390168 14.612403 0 14.481414 11.762375 26.276536 26.243789 26.276536l231.969715 0 0 16.774739c0 38.202647 31.093441 69.296088 69.328835 69.296088 38.202647 0 69.296088-31.093441 69.296088-69.296088l0-16.774739 232.03521 0c14.481414 0 26.243789-11.795122 26.243789-26.276536 0-5.373606-1.605635-10.516959-4.652145-14.875403l-73.096806-97.472983L261.61307 699.311782zM786.461219 613.240955l-550.011281 0 0-188.951187c0-112.348386 68.673891-213.392858 172.142677-255.101499l0-3.113028c0-56.715033 46.164304-102.879337 102.879337-102.879337 56.715033 0 102.84659 46.164304 102.84659 102.879337l0 3.113028c103.468786 41.708641 172.142677 142.753113 172.142677 255.101499L786.461219 613.240955zM270.00044 579.690453l482.910277 0 0-155.400685c0-102.158899-64.67669-193.668827-160.969751-227.677789l-11.172926-3.964455 0-26.571261c0-38.235394-31.093441-69.328835-69.296088-69.328835-38.235394 0-69.328835 31.093441-69.328835 69.328835l0 26.571261-11.172926 3.964455c-96.294085 34.008962-160.969751 125.51889-160.969751 227.677789L270.00044 579.690453z" p-id="2852"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/error.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/error.svg new file mode 100644 index 0000000..fd935da --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/error.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="5914" t="1547360570987" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M234.27218 32h58.36780969v179.99999344h-58.36874719V32zM583.99997844 32h58.27218562v179.99999344H583.99997844V32zM175.99999437 331.99998875h524.59216688v59.99999719H175.99999437v-59.99999719z m0 179.9999925h291.40780125v59.99999812H175.99999437v-59.99999812z m352.55998594 383.999985H32V79.99999812h767.99997v381.6477975C911.16871531 492.99216969 991.9999625 597.1043525 991.9999625 721.99997281c0 149.99999437-116.59218281 269.99998969-262.27217719 269.99998969a258.38436469 258.38436469 0 0 1-201.1199925-95.99999625z m212.35217906-443.75998312V138.31999625H91.08781062v699.35997188H492.36873219A277.72780125 277.72780125 0 0 1 467.40779562 721.99997281c0-149.99999437 116.59218281-269.99998969 262.31998969-269.99998875 3.744375 0 7.4878125 0.095625 11.18437407 0.23999906zM175.99999437 691.99997469h233.13561563v59.99999719H175.99999437v-59.99999719z m553.72779094-179.99999344c-110.73562031 0-203.9999925 95.99999625-203.9999925 209.99999156s93.26437125 209.99999156 203.9999925 209.9999925 203.9999925-95.99999625 203.99999156-209.9999925-93.26343375-209.99999156-203.99999156-209.99999156zM703.99997375 559.99997938h59.75999812v203.99999249H703.99997375V559.99997938z m59.75999812 239.99999062v59.75999812H703.99997375V799.99997h59.75999812z" p-id="5915"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/exit-fullscreen.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/exit-fullscreen.svg new file mode 100644 index 0000000..485c128 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/exit-fullscreen.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M49.217 41.329l-.136-35.24c-.06-2.715-2.302-4.345-5.022-4.405h-3.65c-2.712-.06-4.866 2.303-4.806 5.016l.152 19.164-24.151-23.79a6.698 6.698 0 0 0-9.499 0 6.76 6.76 0 0 0 0 9.526l23.93 23.713-18.345.074c-2.712-.069-5.228 1.813-5.64 5.02v3.462c.069 2.721 2.31 4.97 5.022 5.03l35.028-.207c.052.005.087.025.133.025l2.457.054a4.626 4.626 0 0 0 3.436-1.38c.88-.874 1.205-2.096 1.169-3.462l-.262-2.465c0-.048.182-.081.182-.136h.002zm52.523 51.212l18.32-.073c2.713.06 5.224-1.609 5.64-4.815v-3.462c-.068-2.722-2.317-4.97-5.021-5.04l-34.58.21c-.053 0-.086-.021-.138-.021l-2.451-.06a4.64 4.64 0 0 0-3.445 1.381c-.885.868-1.201 2.094-1.174 3.46l.27 2.46c.005.06-.177.095-.177.141l.141 34.697c.069 2.713 2.31 4.338 5.022 4.397l3.45.006c2.705.062 4.867-2.31 4.8-5.026l-.153-18.752 24.151 23.946a6.69 6.69 0 0 0 9.494 0 6.747 6.747 0 0 0 0-9.523L101.74 92.54v.001zM48.125 80.662a4.636 4.636 0 0 0-3.437-1.382l-2.457.06c-.05 0-.082.022-.137.022l-35.025-.21c-2.712.07-4.957 2.318-5.022 5.04v3.462c.409 3.206 2.925 4.874 5.633 4.814l18.554.06-24.132 23.928c-2.62 2.626-2.62 6.89 0 9.524a6.694 6.694 0 0 0 9.496 0l24.155-23.79-.155 18.866c-.06 2.722 2.094 5.093 4.801 5.025h3.65c2.72-.069 4.962-1.685 5.022-4.406l.141-34.956c0-.05-.182-.082-.182-.136l.262-2.46c.03-1.366-.286-2.592-1.166-3.46h-.001zM80.08 47.397a4.62 4.62 0 0 0 3.443 1.374l2.45-.054c.055 0 .088-.02.143-.028l35.08.21c2.712-.062 4.953-2.312 5.021-5.033l.009-3.463c-.417-3.211-2.937-5.084-5.64-5.025l-18.615-.073 23.917-23.715c2.63-2.623 2.63-6.879.008-9.513a6.691 6.691 0 0 0-9.494 0L92.251 26.016l.155-19.312c.065-2.713-2.097-5.085-4.802-5.025h-3.45c-2.713.069-4.954 1.693-5.022 4.406l-.139 35.247c0 .054.18.088.18.136l-.267 2.465c-.028 1.366.288 2.588 1.174 3.463v.001z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/fullscreen.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/fullscreen.svg new file mode 100644 index 0000000..0e86b6f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/fullscreen.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M38.47 52L52 38.462l-23.648-23.67L43.209 0H.035L0 43.137l14.757-14.865L38.47 52zm74.773 47.726L89.526 76 76 89.536l23.648 23.672L84.795 128h43.174L128 84.863l-14.757 14.863zM89.538 52l23.668-23.648L128 43.207V.038L84.866 0 99.73 14.76 76 38.472 89.538 52zM38.46 76L14.792 99.651 0 84.794v43.173l43.137.033-14.865-14.757L52 89.53 38.46 76z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/fwb.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/fwb.svg new file mode 100644 index 0000000..59933fc --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/fwb.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="2201" t="1545883026424" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path d="M925.597853 836.903811c0.367367-2.783393 0.847298-5.528923 0.847298-8.40953L926.44515 180.091658c19.034519-11.079336 31.976272-31.470759 31.976272-55.082526 0-35.32146-28.633131-63.956637-63.953567-63.956637-23.611767 0-44.007283 12.941753-55.082526 31.980365L182.108594 93.03286c-11.076266-19.038612-31.470759-31.980365-55.082526-31.980365-35.31839 0-63.953567 28.635177-63.953567 63.956637 0 23.611767 12.9438 44.00319 31.976272 55.082526l0 648.402623c0 2.880607 0.479931 5.627161 0.851391 8.40953-19.4991 10.954493-32.827663 31.586392-32.827663 55.543014 0 35.317367 28.635177 63.953567 63.953567 63.953567 35.32146 0 63.953567-28.635177 63.953567-63.953567l639.536698 0c0 35.317367 28.631084 63.953567 63.953567 63.953567 35.319413 0 63.953567-28.635177 63.953567-63.953567C958.421422 868.490204 945.093882 847.859327 925.597853 836.903811zM862.491583 828.494281 159.00234 828.494281 159.00234 180.091658c9.596566-5.586229 17.524119-13.513782 23.110347-23.110347l657.273664 0c5.582135 9.596566 13.509688 17.524119 23.106254 23.110347L862.492606 828.494281z" p-id="2202"/><path d="M670.62781 252.915243 350.86202 252.915243 318.885747 252.915243 286.908452 252.915243 286.908452 380.818285 350.86202 380.818285 350.86202 316.864718 478.768131 316.864718 478.768131 668.610874 414.815587 668.610874 414.815587 732.564441 606.675266 732.564441 606.675266 668.610874 542.721699 668.610874 542.721699 316.864718 670.62781 316.864718 670.62781 380.818285 734.585471 380.818285 734.585471 252.915243 702.609199 252.915243Z" p-id="2203"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/github.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/github.svg new file mode 100644 index 0000000..8145e95 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/github.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1583751668311" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2803" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M263.456 759.36c0 27.04 22.88 40.576 68.672 40.576 40.064 0 60.096-14.048 60.096-42.144 0-26.528-21.856-39.808-65.536-39.808C284.544 718.016 263.456 731.808 263.456 759.36zM853.344 0 170.688 0C76.8 0 0 76.8 0 170.688l0 682.624C0 947.264 76.8 1024 170.688 1024l682.656 0C947.232 1024 1024 947.264 1024 853.312L1024 170.688C1024 76.8 947.232 0 853.344 0zM475.744 408.992c-7.296 2.592-17.696 5.472-31.2 8.576 4.16 11.968 6.24 23.168 6.24 33.568 0 33.28-10.016 62.304-30.048 87.008-20.032 24.704-45.92 39.392-77.632 44.096-20.8 3.136-31.2 14.304-31.2 33.568 0 6.752 3.392 13.536 10.144 20.288 8.832 9.888 21.856 16.128 39.008 18.72 74.4 11.456 111.584 42.4 111.584 92.864 0 80.64-48.128 120.96-144.352 120.96-39.552 0-72.064-7.04-97.536-21.056-32.256-17.696-48.384-45.536-48.384-83.488 0-43.712 24.192-73.6 72.576-89.728l0-1.568c-17.696-10.912-26.528-27.584-26.528-49.952 0-29.12 8.32-47.36 24.96-54.624l0-1.568c-16.64-5.728-31.488-18.72-44.48-39.04-14.56-21.856-21.856-45.248-21.856-70.24 0-37.472 13.28-68.672 39.808-93.632 25.504-23.424 55.936-35.104 91.296-35.104 25.504 0 49.152 6.24 71.008 18.72 24.96 0 53.856-6.24 86.624-18.72L475.744 408.992 475.744 408.992zM602.176 679.008l-88.192 0c1.056-10.4 1.568-28.096 1.568-53.056L515.552 383.232c0-24.448-0.512-41.376-1.568-50.72l88.192 0c-1.056 9.888-1.568 26.272-1.568 49.152l0 239.552C600.608 647.776 601.152 667.04 602.176 679.008zM596.32 254.496c-10.656 11.456-23.296 17.152-37.856 17.152-15.072 0-27.968-5.728-38.624-17.152-10.656-11.456-16-24.96-16-40.576 0-16.128 5.344-29.92 16-41.376 10.656-11.456 23.552-17.152 38.624-17.152 14.56 0 27.2 5.728 37.856 17.152 10.656 11.456 16 25.216 16 41.376C612.32 229.504 606.976 243.04 596.32 254.496zM841.696 668.832c-19.264 10.4-42.4 15.616-69.472 15.616-37.984 0-64.256-13.504-78.816-40.576-10.944-20.288-16.384-52.288-16.384-95.968l0-139.68 0.768 0 0-1.568-11.712-0.768c-6.752 0-15.616 0.768-26.528 2.336L639.584 332.512l38.24 0 0-30.432c0-14.56-0.768-26.272-2.336-35.104l90.528 0c-1.536 9.888-2.336 21.056-2.336 33.536l0 32 67.872 0 0 75.68c-2.592 0-7.424-0.256-14.432-0.768-7.04-0.512-13.664-0.8-19.904-0.8l-33.568 0 0 145.152c0 34.848 11.456 52.288 34.336 52.288 16.128 0 30.688-4.416 43.712-13.248L841.696 668.832 841.696 668.832zM321.216 400.416c-32.768 0-49.152 19.264-49.152 57.76 0 35.904 16.384 53.856 49.152 53.856 31.744 0 47.616-18.208 47.616-54.624 0-15.104-3.648-28.096-10.912-39.008C349.056 406.4 336.832 400.416 321.216 400.416z" p-id="2804"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/gonggao.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/gonggao.svg new file mode 100644 index 0000000..22aed08 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/gonggao.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="1258" t="1554279845314" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path d="M921.9 468.6H749.6c-9.4 0-18.4 3.8-25 10.5-6.6 6.7-10.3 15.7-10.3 25.1v11.1c0 19.6 15.9 35.5 35.4 35.5h172.2c19.5 0 35.3-15.9 35.3-35.5v-11.1c0-9.4-3.7-18.4-10.3-25.1-6.6-6.7-15.6-10.5-25-10.5zM522.4 163.9c-53.6 42.6-165.7 102.3-246.3 159.8h-0.1c-0.9 0.6-1.8 3.8-2.8 4.3-9.5 5.4-13.8 20.1-65.6 20.1h-101c-26 0-42 12.2-42 39.6V631c0 27.4 14.7 40.9 42 40.9H208c51.5 0.1 55.7 14.8 65.2 20.1 0.9 0.5 1.8 3.7 2.7 4.3h0.1c78.2 57.5 191 121.8 246.4 162.7 16.7 12.3 72.1 33.9 72.1-42.1v-614c0-76.1-55.9-51.8-72.1-39z m159 167.8c9.2 16.1 27.3 20.2 40.5 9l141.5-119.3c13.3-11.1 16.5-33.2 7.4-49.4l-5.2-9.1c-9.1-16.1-27.3-20.1-40.5-9L683.6 273.2c-13.2 11.2-16.5 33.2-7.4 49.4l5.2 9.1z m40.4 347.4c-13.2-11.1-31.3-7-40.4 9l-5.2 9.1c-9.1 16.1-5.8 38.2 7.4 49.4L825.1 866c13.2 11.1 31.3 7.1 40.4-9l5.2-9.1c9.1-16.1 5.8-38.2-7.4-49.4L721.8 679.1z m0 0" p-id="1259"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/icon.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/icon.svg new file mode 100644 index 0000000..82fbdd9 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/icon.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="3572" t="1545136555590" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M403.2 780.8V619.2h-160c-89.6 0-161.6 72-161.6 161.6s72 161.6 161.6 161.6 160-72 160-161.6z m81.6 0c0 134.4-108.8 243.2-243.2 243.2S0 915.2 0 780.8s108.8-243.2 243.2-243.2h243.2c-1.6 0-1.6 243.2-1.6 243.2z m134.4 0V619.2h161.6c89.6 0 161.6 72 161.6 161.6s-72 161.6-161.6 161.6-161.6-72-161.6-161.6z m-81.6 0c0 134.4 108.8 243.2 243.2 243.2S1024 915.2 1024 780.8s-108.8-243.2-243.2-243.2H537.6v243.2z m-134.4-537.6v161.6h-160c-89.6 0-161.6-72-161.6-161.6S153.6 81.6 243.2 81.6s160 72 160 161.6z m81.6 0C484.8 108.8 376 0 243.2 0 108.8 1.6 0 108.8 0 243.2s108.8 243.2 243.2 243.2h243.2c-1.6 0-1.6-243.2-1.6-243.2z m134.4 0v161.6h161.6c89.6 0 161.6-72 161.6-161.6S870.4 81.6 780.8 81.6 619.2 153.6 619.2 243.2z m-81.6 0C537.6 108.8 646.4 0 780.8 0c134.4 1.6 241.6 108.8 241.6 243.2s-108.8 243.2-243.2 243.2H537.6v-81.6-161.6z" p-id="3573"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/image.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/image.svg new file mode 100644 index 0000000..16d572f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/image.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="1303" t="1545960873089" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#4A576A" d="M784 112H240C152 112 80 184 80 272v480c0 88 72 160 160 160h544c88 0 160-72 160-160V272c0-88-72-160-160-160z m96 640c0 52.8-43.2 96-96 96H240c-52.8 0-96-43.2-96-96V272c0-52.8 43.2-96 96-96h544c52.8 0 96 43.2 96 96v480z" p-id="1304"/><path fill="#4A576A" d="M352 480c52.8 0 96-43.2 96-96s-43.2-96-96-96-96 43.2-96 96 43.2 96 96 96z m0-128c17.6 0 32 14.4 32 32s-14.4 32-32 32-32-14.4-32-32 14.4-32 32-32zM814.4 731.2l-3.2-3.2-177.6-177.6c-25.6-25.6-65.6-25.6-91.2 0l-80 80-36.8-36.8c-25.6-25.6-65.6-25.6-91.2 0l-134.4 134.4c-4.8 6.4-8 14.4-8 24 0 17.6 14.4 32 32 32 9.6 0 16-3.2 22.4-9.6l134.4-134.4 134.4 134.4c6.4 6.4 14.4 9.6 24 9.6 17.6 0 32-14.4 32-32 0-9.6-4.8-17.6-9.6-24l-52.8-52.8 80-80 180.8 180.8c6.4 4.8 12.8 8 20.8 8 17.6 0 32-14.4 32-32 0-8-3.2-16-8-20.8z" p-id="1305"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/index.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/index.svg new file mode 100644 index 0000000..fdb3826 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/index.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1572170050760" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5149" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400"><defs><style type="text/css"></style></defs><path d="M219.428571 658.285714q0-30.285714-21.428571-51.714285T146.285714 585.142857t-51.714285 21.428572T73.142857 658.285714t21.428572 51.714286T146.285714 731.428571t51.714286-21.428571T219.428571 658.285714z m109.714286-256q0-30.285714-21.428571-51.714285T256 329.142857t-51.714286 21.428572T182.857143 402.285714t21.428571 51.714286T256 475.428571t51.714286-21.428571T329.142857 402.285714z m244.571429 274.857143l57.714285-218.285714q3.428571-14.857143-4.285714-27.714286T605.142857 414.285714t-27.428571 3.714286-17.142857 22.571429l-57.714286 218.285714q-34.285714 2.857143-61.142857 24.857143t-36 56.285714q-11.428571 44 11.428571 83.428571t66.857143 50.857143 83.428571-11.428571 50.857143-66.857143q9.142857-34.285714-3.428571-66.857143t-41.142857-52z m377.142857-18.857143q0-30.285714-21.428572-51.714285T877.714286 585.142857t-51.714286 21.428572-21.428571 51.714285 21.428571 51.714286 51.714286 21.428571 51.714285-21.428571 21.428572-51.714286z m-365.714286-365.714285q0-30.285714-21.428571-51.714286T512 219.428571t-51.714286 21.428572T438.857143 292.571429t21.428571 51.714285T512 365.714286t51.714286-21.428572T585.142857 292.571429z m256 109.714285q0-30.285714-21.428571-51.714285T768 329.142857t-51.714286 21.428572T694.857143 402.285714t21.428571 51.714286T768 475.428571t51.714286-21.428571T841.142857 402.285714z m182.857143 256q0 149.142857-80.571429 276-10.857143 16.571429-30.857142 16.571429H111.428571q-20 0-30.857142-16.571429Q0 808 0 658.285714q0-104 40.571429-198.857143t109.142857-163.428571 163.428571-109.142857 198.857143-40.571429 198.857143 40.571429 163.428571 109.142857 109.142857 163.428571 40.571429 198.857143z" p-id="5150" fill="#bfbfbf"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/international.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/international.svg new file mode 100644 index 0000000..e9b56ee --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/international.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M83.287 103.01c-1.57-3.84-6.778-10.414-15.447-19.548-2.327-2.444-2.182-4.306-1.338-9.862v-.64c.553-3.81 1.513-6.05 14.313-8.087 6.516-1.018 8.203 1.57 10.589 5.178l.785 1.193a12.625 12.625 0 0 0 6.43 5.207c1.134.524 2.53 1.164 4.421 2.24 4.596 2.53 4.596 5.41 4.596 11.753v.727a26.91 26.91 0 0 1-5.178 17.454 59.055 59.055 0 0 1-19.025 11.026c3.49-6.546.814-14.313 0-16.553l-.146-.087zM64 5.12a58.502 58.502 0 0 1 25.484 5.818 54.313 54.313 0 0 0-12.859 10.327c-.93 1.28-1.716 2.473-2.472 3.579-2.444 3.694-3.637 5.352-5.818 5.614a25.105 25.105 0 0 1-4.219 0c-4.276-.29-10.094-.64-11.956 4.422-1.193 3.23-1.396 11.956 2.444 16.495.66 1.077.778 2.4.32 3.578a7.01 7.01 0 0 1-2.066 3.229 18.938 18.938 0 0 1-2.909-2.91 18.91 18.91 0 0 0-8.32-6.603c-1.25-.349-2.647-.64-3.985-.93-3.782-.786-8.03-1.688-9.019-3.812a14.895 14.895 0 0 1-.727-5.818 21.935 21.935 0 0 0-1.396-9.25 8.873 8.873 0 0 0-5.557-4.946A58.705 58.705 0 0 1 64 5.12zM0 64c0 35.346 28.654 64 64 64 35.346 0 64-28.654 64-64 0-35.346-28.654-64-64-64C28.654 0 0 28.654 0 64z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/ipvisits.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/ipvisits.svg new file mode 100644 index 0000000..4ca473d --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/ipvisits.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="5670" t="1544682877339" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path d="M449.98144 243.90144c-57.7536-10.624-121.00096-7.98208-167.65952 6.8352C195.92192 278.19008 146.95936 329.984 119.76192 406.528c-32.22528 90.69568-2.93376 190.62784 15.81056 248.63744 18.74432 58.0096 76.0576 144.97792 135.94112 155.8528 63.7696 11.58144 121.30816-9.89696 155.37664-50.7392 16.05632-19.24608 30.27456-46.75072 31.70816-74.46016 0.93184-18.0224-1.22368-31.64672-6.1696-45.14816-5.64224-15.40096-15.06816-29.6448-32.95232-46.57664-19.18976-18.17088-62.53056-34.09408-104.28416-28.29312-30.90432 4.29056-56.55552 15.67744-78.4384 32.47616-33.5872 25.78944-65.41312 82.65728-65.41312 82.65728s-1.152-33.25952 13.27104-66.69824c7.22944-16.75264 24.3968-44.8512 41.26208-58.99776 17.12128-14.36672 37.85728-31.5392 72.1664-40.32 38.8864-9.95328 78.27456-6.97856 93.62944-3.5584 46.39744 10.32192 82.24256 34.64704 111.616 65.32096 59.52512 62.16704 82.46784 161.536 51.75296 246.03648-10.28096 28.28288-38.85056 61.06112-69.30944 85.10976-18.32448 14.464-57.00096 35.4048-103.18848 45.14304-30.592 6.4512-64.48128 6.2976-97.93536 2.2272-83.95776-10.22464-159.50336-86.53312-195.11296-147.77856-35.61472-61.24544-89.0368-186.05568-75.80672-320.60928 6.30272-64.12288 28.08832-132.46976 62.88384-182.4768C114.77504 249.3952 167.1168 215.15264 194.80576 199.13216c52.89984-30.60736 132.29056-43.6224 185.19552-40.832 33.62816 1.77664 86.85568 12.66688 137.27232 38.08768 39.66464 20.00384 75.78112 55.2448 92.17536 95.37536 9.81504 24.02304 6.71232 47.49312 6.67136 47.49312-0.04608 0.11776 1.13664-2.54464-31.44192-34.05312C557.16352 278.59456 507.72992 254.53056 449.98144 243.90144L449.98144 243.90144z" p-id="5671"/><path d="M559.07328 155.18208c0 0 37.8624-68.5056 72.36096-88.50944 34.49856-20.00384 61.65504-7.67488 79.4624 5.92896 17.81248 13.60384 26.82368 30.91456 22.912 55.552-3.91168 24.63744-43.14624 71.76192-66.3296 106.22976C631.34208 207.98464 595.21024 181.58592 559.07328 155.18208L559.07328 155.18208z" p-id="5672"/><path d="M408.26368 117.03296c0 0 6.8096-62.65344 26.31168-88.04864 19.50208-25.3952 43.65824-24.41216 61.23008-19.64544 17.57184 4.76672 29.73184 14.97088 34.53952 34.56 4.80256 19.59424-9.73312 66.688-16.24576 99.46112C478.81728 134.58944 443.54048 125.80864 408.26368 117.03296L408.26368 117.03296z" p-id="5673"/><path d="M294.76352 125.06112c0 0-11.65824-45.60896-4.6592-68.34176 7.00416-22.72768 24.17664-28.16 37.7344-29.27104 13.55776-1.11104 24.7552 2.94912 33.2544 15.45728 8.4992 12.50304 10.66496 49.17248 14.69952 73.78432C348.78464 119.48032 321.77152 122.27072 294.76352 125.06112L294.76352 125.06112z" p-id="5674"/><path d="M185.1648 163.1232c0 0-20.89984-34.67264-20.79232-55.01952 0.10752-20.352 12.86656-28.93312 23.7312-33.1008 10.85952-4.16768 21.06368-3.51744 31.1552 4.72064 10.09152 8.23296 20.97152 37.8368 30.39744 57.08288C228.15744 145.57696 206.66368 154.35264 185.1648 163.1232L185.1648 163.1232z" p-id="5675"/><path d="M97.408 227.1488c0 0-26.7776-25.18528-31.72352-42.9312-4.9408-17.74592 4.0448-28.26752 12.47232-34.49344 8.4224-6.22592 17.46944-8.09472 28.29312-3.34336 10.81856 4.75648 27.6224 27.9296 40.59136 42.42944C130.49856 201.58976 113.95584 214.36928 97.408 227.1488L97.408 227.1488z" p-id="5676"/><path d="M762.08128 537.68704c38.15424 4.096 77.2864 17.52064 103.7568 35.49696 49.01376 33.28 70.04672 74.84416 72.832 127.85664 3.3024 62.81216-33.65376 119.96672-56.192 152.81664-22.53824 32.84992-74.63424 76.66176-114.17088 72.33024-42.10176-4.61824-74.15296-28.78464-87.88992-60.71296-6.4768-15.04768-10.2656-34.92864-6.00576-52.55168 2.76992-11.46368 6.656-19.59936 12.27264-27.136 6.40512-8.59648 14.96064-15.76448 29.312-23.04512 15.40608-7.81312 45.52192-9.71776 70.59456 1.6896 18.56 8.44288 32.512 20.352 43.08992 34.94912 16.24064 22.41024 25.59488 63.95904 25.59488 63.95904s6.91712-20.61824 4.10112-44.25216c-1.408-11.83744-6.93248-32.64-14.86336-44.64128-8.05376-12.1856-17.8432-26.80832-37.70368-38.69696-22.50752-13.47072-47.73376-18.944-57.98912-19.6608-30.98624-2.17088-57.97376 6.39488-82.07872 20.14208-48.86016 27.86304-81.73056 85.84192-78.22336 144.49664 1.17248 19.63008 12.96896 45.48608 27.57632 66.21696 8.78592 12.47232 29.11744 32.78848 56.23808 47.49312 17.96608 9.73824 39.22432 15.9488 60.93824 19.62496 54.49728 9.22624 116.02944-24.51456 149.74464-56.25344 33.71008-31.73888 90.41408-99.98336 107.17696-186.73664 7.9872-41.33888 7.06048-88.2176-5.42208-126.02368-13.71136-41.5232-40.12544-72.71424-54.49216-87.90528-27.4432-29.02016-74.752-51.95776-108.416-60.0576-21.39136-5.1456-56.77056-8.23296-93.08672-1.69472-28.57472 5.14048-57.75872 20.50048-75.49952 42.58816-10.61888 13.22496-13.04576 28.50304-13.04576 28.50304s-0.21504-1.79712 26.06592-15.47264C688.47616 539.46368 723.92192 533.59104 762.08128 537.68704L762.08128 537.68704z" p-id="5677"/><path d="M710.25664 461.7984c0 0-10.96704-49.96608-28.85632-68.92032-17.88416-18.94912-37.19168-16.2816-50.88256-11.07968-13.69088 5.20704-22.55872 14.37184-24.69376 30.53568-2.13504 16.16384 13.66528 52.98688 21.77536 78.8992C655.15008 481.42336 682.70592 471.60832 710.25664 461.7984L710.25664 461.7984z" p-id="5678"/><path d="M811.83232 465.97632c0 0 7.3984-40.51456-0.09216-60.0576-7.49056-19.54304-22.80448-23.424-34.70336-23.71072-11.89888-0.28672-21.41696 3.84512-28.07296 15.22176-6.656 11.37664-6.31808 43.58656-8.34048 65.3312C764.3648 463.83616 788.10112 464.90624 811.83232 465.97632L811.83232 465.97632z" p-id="5679"/><path d="M881.43872 492.1344c0 0 15.7952-26.40384 15.6416-41.94304-0.1536-15.54432-9.9072-22.144-18.19136-25.36448-8.28928-3.22048-16.05632-2.75968-23.71072 3.49184-7.64928 6.25152-15.83616 28.82048-22.94272 43.48416C848.64 478.58176 865.03936 485.35552 881.43872 492.1344L881.43872 492.1344z" p-id="5680"/><path d="M943.01184 536.38144c0 0 19.54816-17.82784 23.2704-30.59712 3.72224-12.76928-2.67264-20.52096-8.704-25.15456-6.03136-4.6336-12.53888-6.12352-20.39296-2.8416-7.85408 3.2768-20.18304 19.79904-29.6704 30.10048C919.3472 517.38624 931.17952 526.88384 943.01184 536.38144L943.01184 536.38144z" p-id="5681"/><path d="M986.07104 592.82432c0 0 21.46304-10.79296 27.86304-20.992 6.4-10.19392 2.72896-18.46272-1.39264-23.93088-4.11648-5.46816-9.43616-8.32512-17.1008-7.36256-7.66464 0.96256-22.50752 12.35456-33.3312 19.0208C970.09664 570.65472 978.08384 581.73952 986.07104 592.82432L986.07104 592.82432z" p-id="5682"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/java.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/java.svg new file mode 100644 index 0000000..e2effbb --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/java.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="749" t="1547192680027" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M377.596784 791.989528s-39.199482 22.799699 27.799633 30.399598c81.198926 9.199878 122.598379 7.999894 211.997197-8.999881 0 0 23.599688 14.799804 56.399254 27.599635C473.395518 926.787745 220.198866 835.988946 377.596784 791.989528m-24.399677-112.198517s-43.799421 32.399572 23.199693 39.399479c86.598855 8.999881 155.197948 9.599873 273.596382-13.199825 0 0 16.399783 16.599781 42.199442 25.599661-242.596792 70.999061-512.593222 5.799923-338.995517-51.799315m206.397271-190.197485c49.399347 56.799249-12.999828 107.998572-12.999828 107.998572s125.398342-64.799143 67.799103-145.798072c-53.799289-75.599-94.998744-113.198503 128.198305-242.596792 0.199997 0-350.395367 87.598842-182.99758 280.396292m265.196493 385.194907s28.999617 23.799685-31.799579 42.399439c-115.798469 34.999537-481.593632 45.599397-583.192289 1.399982-36.599516-15.799791 31.999577-37.999498 53.599291-42.599437 22.399704-4.799937 35.399532-3.999947 35.399532-3.999947-40.599463-28.599622-262.596528 56.199257-112.798508 80.398937 408.3946 66.399122 744.790152-29.799606 638.791553-77.598974M396.396536 563.592548s-186.197538 44.199416-65.999128 60.199204c50.799328 6.79991 151.99799 5.199931 246.196745-2.599966 76.998982-6.399915 154.397958-20.39973 154.397958-20.39973s-27.19964 11.599847-46.799381 24.999669c-188.997501 49.799342-553.992675 26.599648-448.994063-24.19968 88.998823-42.799434 161.197869-37.999498 161.197869-37.999497m333.995583 186.597532c192.197459-99.79868 103.198635-195.797411 41.199456-182.797582-15.199799 3.199958-21.999709 5.999921-21.999709 5.99992s5.599926-8.799884 16.399783-12.599833c122.598379-43.199429 216.997131 127.198318-39.599477 194.597427 0-0.199997 2.99996-2.799963 3.999947-5.199932M614.393653 0s106.398593 106.398593-100.998664 269.99643c-166.197802 131.198265-37.999498 206.197274 0 291.596144-96.998717-87.598842-168.197776-164.597824-120.398408-236.396874C463.195652 220.197088 657.393085 168.997765 614.393653 0m-198.997369 1020.786502c184.397562 11.799844 467.593817-6.599913 474.19373-93.798759 0 0-12.799831 32.999564-152.397985 59.399214-157.397919 29.599609-351.595351 26.199654-466.59383 7.199905 0-0.199997 23.599688 19.399743 144.798085 27.19964" p-id="750"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/link.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/link.svg new file mode 100644 index 0000000..48197ba --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/link.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.625 127.937H.063V12.375h57.781v12.374H12.438v90.813h90.813V70.156h12.374z"/><path d="M116.426 2.821l8.753 8.753-56.734 56.734-8.753-8.745z"/><path d="M127.893 37.982h-12.375V12.375H88.706V0h39.187z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/list.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/list.svg new file mode 100644 index 0000000..20259ed --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/list.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M1.585 12.087c0 6.616 3.974 11.98 8.877 11.98 4.902 0 8.877-5.364 8.877-11.98 0-6.616-3.975-11.98-8.877-11.98-4.903 0-8.877 5.364-8.877 11.98zM125.86.107H35.613c-1.268 0-2.114 1.426-2.114 2.852v18.255c0 1.712 1.057 2.853 2.114 2.853h90.247c1.268 0 2.114-1.426 2.114-2.853V2.96c0-1.711-1.057-2.852-2.114-2.852zM.106 62.86c0 6.615 3.974 11.979 8.876 11.979 4.903 0 8.877-5.364 8.877-11.98 0-6.616-3.974-11.98-8.877-11.98-4.902 0-8.876 5.364-8.876 11.98zM124.17 50.88H33.921c-1.268 0-2.114 1.425-2.114 2.851v18.256c0 1.711 1.057 2.852 2.114 2.852h90.247c1.268 0 2.114-1.426 2.114-2.852V53.73c0-1.426-.846-2.852-2.114-2.852zM.106 115.913c0 6.616 3.974 11.98 8.876 11.98 4.903 0 8.877-5.364 8.877-11.98 0-6.616-3.974-11.98-8.877-11.98-4.902 0-8.876 5.364-8.876 11.98zm124.064-11.98H33.921c-1.268 0-2.114 1.426-2.114 2.853v18.255c0 1.711 1.057 2.852 2.114 2.852h90.247c1.268 0 2.114-1.426 2.114-2.852v-18.255c0-1.427-.846-2.853-2.114-2.853z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/lock.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/lock.svg new file mode 100644 index 0000000..0f842ea --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/lock.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="3654" t="1545700954682" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path d="M868.935 1008.63l-713.868 0c-40.657 0-72.291-31.631-72.291-67.773l0-496.994c0-36.144 31.631-67.773 72.291-67.773l713.868 0c40.657 0 72.291 31.631 72.291 67.773l0 496.994c0 36.144-31.631 67.773-72.291 67.773l0 0 0 0 0 0zM512 543.259c-58.732 0-108.432 45.187-108.432 99.402 0 36.144 22.586 67.773 54.218 85.849l0 94.887c0 27.108 22.586 49.696 54.218 49.696s54.218-22.586 54.218-49.696l0-94.887c31.631-18.071 54.218-49.696 54.218-85.849 0-54.218-49.696-99.402-108.432-99.402l0 0 0 0zM512 114.031c-117.471 0-216.867 90.356-216.867 198.797l-108.432 0c0-162.655 144.582-298.202 320.79-298.202s320.79 135.546 320.79 298.202l-108.432 0c9.041-112.951-90.356-198.797-207.836-198.797l0 0 0 0zM512 114.031z" p-id="3655"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/log.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/log.svg new file mode 100644 index 0000000..4fefe74 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/log.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="4026" t="1547360510388" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M787.692308 275.692308V78.769231c0-43.323077-35.446154-78.769231-78.769231-78.769231H78.769231C35.446154 0 0 35.446154 0 78.769231v866.461538c0 43.323077 35.446154 78.769231 78.769231 78.769231h354.461538v-39.384615H78.769231c-19.692308 0-39.384615-15.753846-39.384616-39.384616V78.769231c0-23.630769 15.753846-39.384615 39.384616-39.384616h630.153846c19.692308 0 39.384615 15.753846 39.384615 39.384616v196.923077h39.384616z" p-id="4027"/><path fill="#bfbfbf" d="M137.846154 472.615385h196.923077c11.815385 0 19.692308 7.876923 19.692307 19.692307s-7.876923 19.692308-19.692307 19.692308h-196.923077c-11.815385 0-19.692308-7.876923-19.692308-19.692308s7.876923-19.692308 19.692308-19.692307zM137.846154 669.538462h118.153846c11.815385 0 19.692308 7.876923 19.692308 19.692307s-7.876923 19.692308-19.692308 19.692308h-118.153846c-11.815385 0-19.692308-7.876923-19.692308-19.692308s7.876923-19.692308 19.692308-19.692307zM137.846154 275.692308h354.461538c11.815385 0 19.692308 7.876923 19.692308 19.692307s-7.876923 19.692308-19.692308 19.692308h-354.461538c-11.815385 0-19.692308-7.876923-19.692308-19.692308s7.876923-19.692308 19.692308-19.692307zM716.8 433.230769c7.876923 0 19.692308 0 31.507692 3.938462 0 3.938462 3.938462 11.815385 3.938462 19.692307 3.938462 23.630769 11.815385 63.015385 55.138461 78.769231 7.876923 3.938462 15.753846 3.938462 19.692308 3.938462 31.507692 0 51.2-19.692308 66.953846-35.446154l11.815385-11.815385c43.323077 19.692308 66.953846 51.2 70.892308 98.461539-3.938462 3.938462-11.815385 7.876923-19.692308 7.876923-15.753846 7.876923-51.2 27.569231-51.2 70.892308s39.384615 63.015385 63.015384 74.830769c3.938462 3.938462 11.815385 7.876923 19.692308 7.876923-3.938462 47.261538-27.569231 74.830769-74.830769 98.461538l-11.815385-11.815384c-15.753846-15.753846-35.446154-31.507692-66.953846-31.507693-7.876923 0-15.753846 0-23.630769 3.938462-43.323077 11.815385-51.2 51.2-55.138462 74.830769 0 3.938462-3.938462 11.815385-3.938461 15.753846-11.815385 0-19.692308 3.938462-31.507692 3.938462-35.446154 0-63.015385-11.815385-86.646154-39.384616 0-3.938462 3.938462-11.815385 7.876923-15.753846 11.815385-23.630769 31.507692-59.076923 3.938461-94.523077-7.876923-11.815385-27.569231-27.569231-63.015384-27.56923-11.815385 0-19.692308 0-31.507693 3.938461-7.876923 0-15.753846 3.938462-19.692307 3.938462-23.630769-43.323077-23.630769-78.769231 0-122.092308 3.938462 0 11.815385 0 19.692307 3.938462 7.876923 0 19.692308 3.938462 31.507693 3.938461 31.507692 0 51.2-15.753846 63.015384-27.569231 27.569231-35.446154 7.876923-74.830769-3.938461-94.523077-3.938462-3.938462-7.876923-11.815385-7.876923-15.753846 23.630769-39.384615 51.2-51.2 82.707692-51.2m0-39.384615c-47.261538 0-82.707692 19.692308-118.153846 55.138461-27.569231 31.507692 35.446154 78.769231 11.815384 110.276923-7.876923 11.815385-19.692308 11.815385-31.507692 11.815385-15.753846 0-35.446154-3.938462-51.2-3.938461-11.815385 0-23.630769 3.938462-31.507692 15.753846-31.507692 55.138462-31.507692 110.276923 0 169.353846 7.876923 11.815385 19.692308 15.753846 31.507692 15.753846 15.753846 0 35.446154-3.938462 51.2-3.938462 11.815385 0 23.630769 3.938462 31.507692 11.815385 23.630769 35.446154-43.323077 78.769231-11.815384 110.276923 35.446154 39.384615 74.830769 55.138462 122.092308 55.138462 11.815385 0 27.569231 0 43.323076-3.938462 43.323077-7.876923 19.692308-78.769231 59.076924-94.523077h7.876923c31.507692 0 51.2 47.261538 78.76923 47.261539 3.938462 0 7.876923 0 11.815385-3.938462 63.015385-27.569231 94.523077-70.892308 102.4-133.907692 3.938462-43.323077-78.769231-43.323077-78.769231-82.707692 0-43.323077 82.707692-39.384615 78.769231-82.707693-7.876923-63.015385-39.384615-110.276923-102.4-133.907692-3.938462 0-7.876923-3.938462-11.815385-3.938462-31.507692 0-51.2 51.2-82.707692 51.2h-7.876923c-39.384615-11.815385-15.753846-86.646154-59.076923-98.461538-15.753846-7.876923-27.569231-7.876923-43.323077-7.876923z" p-id="4028"/><path fill="#bfbfbf" d="M748.307692 590.769231c43.323077 0 78.769231 35.446154 78.769231 78.769231s-35.446154 78.769231-78.769231 78.76923-78.769231-35.446154-78.76923-78.76923 35.446154-78.769231 78.76923-78.769231m0-39.384616c-66.953846 0-118.153846 51.2-118.153846 118.153847s51.2 118.153846 118.153846 118.153846 118.153846-51.2 118.153846-118.153846-51.2-118.153846-118.153846-118.153847z" p-id="4029"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/login.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/login.svg new file mode 100644 index 0000000..cc5a854 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/login.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575115830633" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2251" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M409.002667 469.333333L300.8 361.130667 361.130667 300.8l211.2 211.2-211.2 211.2-60.330667-60.330667L409.002667 554.666667H128v-85.333334h281.002667zM469.333333 128h341.333334c46.933333 0 85.333333 38.4 85.333333 85.333333v597.333334c0 46.933333-38.4 85.333333-85.333333 85.333333h-341.333334v-85.333333h341.333334V213.333333h-341.333334V128z" fill="#cdcdcd" p-id="2252"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/markdown.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/markdown.svg new file mode 100644 index 0000000..7cd6747 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/markdown.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="983" t="1552025141027" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M895.318 192H128.682C93.008 192 64 220.968 64 256.616v510.698C64 802.986 93.008 832 128.682 832h766.636C930.992 832 960 802.986 960 767.312V256.616C960 220.968 930.992 192 895.318 192zM568.046 704h-112.096v-192l-84.08 107.756L287.826 512v192H175.738V320h112.088l84.044 135.96 84.08-135.96h112.096v384z m167.314 0l-139.27-192h84v-192h112.086v192h84.054l-140.906 192h0.036z" p-id="984"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/menu.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/menu.svg new file mode 100644 index 0000000..e4360a0 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/menu.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="2559" t="1545037285158" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path d="M96 128h832v192H96zM96 416h832v192H96zM96 704h832v192H96z" p-id="2560"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/message.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/message.svg new file mode 100644 index 0000000..14ca817 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/message.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 20.967v59.59c0 11.59 8.537 20.966 19.075 20.966h28.613l1 26.477L76.8 101.523h32.125c10.538 0 19.075-9.377 19.075-20.966v-59.59C128 9.377 119.463 0 108.925 0h-89.85C8.538 0 0 9.377 0 20.967zm82.325 33.1c0-5.524 4.013-9.935 9.037-9.935 5.026 0 9.038 4.41 9.038 9.934 0 5.524-4.025 9.934-9.038 9.934-5.024 0-9.037-4.41-9.037-9.934zm-27.613 0c0-5.524 4.013-9.935 9.038-9.935s9.037 4.41 9.037 9.934c0 5.524-4.025 9.934-9.037 9.934-5.025 0-9.038-4.41-9.038-9.934zm-27.1 0c0-5.524 4.013-9.935 9.038-9.935s9.038 4.41 9.038 9.934c0 5.524-4.026 9.934-9.05 9.934-5.013 0-9.025-4.41-9.025-9.934z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/mnt.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/mnt.svg new file mode 100644 index 0000000..936ce29 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/mnt.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1649727721107" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="21653" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M554.666667 896v85.333333h-85.333334v-85.333333h-341.333333A42.666667 42.666667 0 0 1 85.333333 853.333333V256h853.333334V853.333333a42.666667 42.666667 0 0 1-42.666667 42.666667h-341.333333zM341.333333 426.666667a128 128 0 1 0 128 128H341.333333V426.666667z m213.333334 0V512h256V426.666667h-256z m0 170.666666V682.666667h256v-85.333334h-256zM85.333333 128h853.333334v85.333333h-853.333334v-85.333333z" p-id="21654" fill="#bfbfbf"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/money.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/money.svg new file mode 100644 index 0000000..c1580de --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/money.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.122 127.892v-28.68H7.513V87.274h46.609v-12.4H7.513v-12.86h38.003L.099 0h22.6l32.556 45.07c3.617 5.144 6.44 9.611 8.487 13.385 1.788-3.05 4.89-7.779 9.301-14.186L103.93 0h24.01L82.385 62.013h38.34v12.862h-46.41v12.4h46.41v11.937h-46.41v28.68H54.123z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/monitor.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/monitor.svg new file mode 100644 index 0000000..339370a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/monitor.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1649727681286" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20343" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M874.666667 106.666667H149.333333c-23.466667 0-42.666667 19.2-42.666666 42.666666v469.333334h810.666666V149.333333c0-23.466667-19.2-42.666667-42.666666-42.666666zM384 469.333333c0 23.466667-19.2 42.666667-42.666667 42.666667h-42.666666c-23.466667 0-42.666667-19.2-42.666667-42.666667v-64c0-23.466667 19.2-42.666667 42.666667-42.666666h42.666666c23.466667 0 42.666667 19.2 42.666667 42.666666v64z m192 0c0 23.466667-19.2 42.666667-42.666667 42.666667h-42.666666c-23.466667 0-42.666667-19.2-42.666667-42.666667v-128c0-23.466667 19.2-42.666667 42.666667-42.666666h42.666666c23.466667 0 42.666667 19.2 42.666667 42.666666v128z m192 0c0 23.466667-19.2 42.666667-42.666667 42.666667h-42.666666c-23.466667 0-42.666667-19.2-42.666667-42.666667V256c0-23.466667 19.2-42.666667 42.666667-42.666667h42.666666c23.466667 0 42.666667 19.2 42.666667 42.666667v213.333333zM106.666667 725.333333c0 23.466667 19.2 42.666667 42.666666 42.666667h213.333334v85.333333h-138.666667c-17.066667 0-32 14.933333-32 32s14.933333 32 32 32h576c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32H661.333333v-85.333333h213.333334c23.466667 0 42.666667-19.2 42.666666-42.666667v-42.666666H106.666667v42.666666z" p-id="20344"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/nested.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/nested.svg new file mode 100644 index 0000000..06713a8 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/nested.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.002 9.2c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-5.043-3.58-9.132-7.997-9.132S.002 4.157.002 9.2zM31.997.066h95.981V18.33H31.997V.066zm0 45.669c0 5.044 3.58 9.132 7.998 9.132 4.417 0 7.997-4.088 7.997-9.132 0-3.263-1.524-6.278-3.998-7.91-2.475-1.63-5.524-1.63-7.998 0-2.475 1.632-4 4.647-4 7.91zM63.992 36.6h63.986v18.265H63.992V36.6zm-31.995 82.2c0 5.043 3.58 9.132 7.998 9.132 4.417 0 7.997-4.089 7.997-9.132 0-5.044-3.58-9.133-7.997-9.133s-7.998 4.089-7.998 9.133zm31.995-9.131h63.986v18.265H63.992V109.67zm0-27.404c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-3.263-1.524-6.277-3.998-7.909-2.475-1.631-5.524-1.631-7.998 0-2.475 1.632-4 4.646-4 7.91zm31.995-9.13h31.991V91.4H95.987V73.135z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/password.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/password.svg new file mode 100644 index 0000000..4ab451f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/password.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="3833" t="1561614515233" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#8a8a8a" d="M807.049 391.258c0.946-9.62 1.45-19.37 1.45-29.239 0-163.7-132.706-296.406-296.406-296.406S215.687 198.318 215.687 362.02c0 9.802 0.498 19.486 1.432 29.043-43.925 18.95-74.675 62.638-74.675 113.516v330.363c0 68.25 55.328 123.58 123.58 123.58h491.672c68.25 0 123.578-55.328 123.578-123.58V504.578c0-50.704-30.54-94.267-74.225-113.32zM510.917 165.905c109.134 0 197.604 88.47 197.604 197.603 0 5.895-0.275 11.726-0.782 17.49H314.094a200.097 200.097 0 0 1-0.782-17.49c0.002-109.132 88.472-197.603 197.605-197.603z" p-id="3834"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/people.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/people.svg new file mode 100644 index 0000000..2bd54ae --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/people.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M104.185 95.254c8.161 7.574 13.145 17.441 13.145 28.28 0 1.508-.098 2.998-.285 4.466h-10.784c.238-1.465.403-2.948.403-4.465 0-8.983-4.36-17.115-11.419-23.216C86 104.66 75.355 107.162 64 107.162c-11.344 0-21.98-2.495-31.22-6.83-7.064 6.099-11.444 14.218-11.444 23.203 0 1.517.165 3 .403 4.465H10.955a35.444 35.444 0 0 1-.285-4.465c0-10.838 4.974-20.713 13.127-28.291C9.294 85.42.003 70.417.003 53.58.003 23.99 28.656.001 64 .001s63.997 23.988 63.997 53.58c0 16.842-9.299 31.85-23.812 41.673zM64 36.867c-29.454 0-53.33-10.077-53.33 15.342 0 25.418 23.876 46.023 53.33 46.023 29.454 0 53.33-20.605 53.33-46.023 0-25.419-23.876-15.342-53.33-15.342zm24.888 25.644c-3.927 0-7.111-2.665-7.111-5.953 0-3.288 3.184-5.954 7.11-5.954 3.928 0 7.111 2.666 7.111 5.954s-3.183 5.953-7.11 5.953zm-3.556 16.372c0 4.11-9.55 7.442-21.332 7.442-11.781 0-21.332-3.332-21.332-7.442 0-1.06.656-2.064 1.8-2.976 3.295 2.626 10.79 4.465 19.532 4.465 8.743 0 16.237-1.84 19.531-4.465 1.145.912 1.801 1.916 1.801 2.976zm-46.22-16.372c-3.927 0-7.11-2.665-7.11-5.953 0-3.288 3.183-5.954 7.11-5.954 3.927 0 7.111 2.666 7.111 5.954s-3.184 5.953-7.11 5.953z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/peoples.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/peoples.svg new file mode 100644 index 0000000..2c91161 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/peoples.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><g><path d="M95.648 118.762c0 5.035-3.563 9.121-7.979 9.121H7.98c-4.416 0-7.979-4.086-7.979-9.121C0 100.519 15.408 83.47 31.152 76.75c-9.099-6.43-15.216-17.863-15.216-30.987v-9.128c0-20.16 14.293-36.518 31.893-36.518s31.894 16.358 31.894 36.518v9.122c0 13.137-6.123 24.556-15.216 30.993 15.738 6.726 31.141 23.769 31.141 42.012z"/><path d="M106.032 118.252h15.867c3.376 0 6.101-3.125 6.101-6.972 0-13.957-11.787-26.984-23.819-32.123 6.955-4.919 11.638-13.66 11.638-23.704v-6.985c0-15.416-10.928-27.926-24.39-27.926-1.674 0-3.306.193-4.89.561 1.936 4.713 3.018 9.974 3.018 15.526v9.121c0 13.137-3.056 23.111-11.066 30.993 14.842 4.41 27.312 23.42 27.541 41.509z"/></g></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/permission.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/permission.svg new file mode 100644 index 0000000..c4c7409 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/permission.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="3778" t="1543477660371" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css">@font-face{font-family:rbicon;src:url(chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2) format("woff2");font-weight:400;font-style:normal}</style></defs><path d="M418.496 705.6 383.296 705.6l0-53.248 0 0C384 484.48 257.28 503.808 255.872 503.808L255.488 503.744c-133.504 0-125.632 146.112-125.632 148.608l0 53.248L91.84 705.6C76.032 705.6 64 716.864 64 731.52l0 201.152c0 14.72 12.032 25.856 27.84 25.856l326.656 0c15.808 0 28.096-11.136 28.096-25.856L446.592 731.52C446.592 716.864 434.24 705.6 418.496 705.6zM175.936 652.352c0-0.448-4.928-100.8 77.376-100.8 7.296 0.256 78.144-4.032 78.144 100.8l0 53.248-155.52 0L175.936 652.352zM960 889.024c0 61.12-77.824 69.504-77.824 69.504L635.776 958.528l-80.64 0c0 0-41.088 0.96-41.088-39.168l-1.344-196.928C514.304 533.376 464 464.768 348.8 427.264c-33.344-24.96-47.168-31.296-47.168-78.528 0-47.232 38.848-47.232 38.848-47.232s0 1.344 13.824-76.416c13.44-75.456 87.232-155.968 208.32-160.64L562.624 64c1.792 0 3.456 0.192 5.248 0.192C569.856 64.192 571.776 64 573.824 64l0 0.512c105.28 5.312 181.056 85.44 194.432 160.576 13.888 77.76 13.888 76.416 13.888 76.416s38.848 0 38.848 47.232c0 47.232-13.824 63.936-47.168 88.896C740.48 462.656 750.4 516.48 698.88 563.968c-27.52 25.344-47.232 44.48-47.232 80.64 0 36.032 19.456 44.352 38.848 55.488s150.016 47.232 211.136 88.96S960 852.928 960 889.024z" p-id="3779"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/phone.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/phone.svg new file mode 100644 index 0000000..da339f9 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/phone.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="1989" t="1554009861477" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#8a8a8a" d="M756.081 1012.218 291.154 1012.218c-68.473 0-123.982-55.975-123.982-125.054L167.172 136.836c0-69.078 55.512-125.054 123.982-125.054l464.928 0c68.474 0 123.984 55.975 123.984 125.054l0 750.328C880.066 956.242 824.555 1012.218 756.081 1012.218L756.081 1012.218zM818.062 136.836c0-34.516-27.751-62.526-61.98-62.526L291.154 74.31c-34.228 0-61.991 28.01-61.991 62.526l0 31.268 588.899 0L818.062 136.836 818.062 136.836zM818.062 230.63 229.163 230.63l0 499.242 588.899 0L818.062 230.63 818.062 230.63zM818.062 792.398 229.163 792.398l0 94.766c0 34.54 27.765 62.526 61.991 62.526l464.928 0c34.229 0 61.98-27.986 61.98-62.526L818.062 792.398 818.062 792.398zM523.623 918.429c-25.668 0-46.482-20.993-46.482-46.896 0-25.903 20.816-46.895 46.482-46.895 25.664 0 46.477 20.993 46.477 46.895S549.287 918.429 523.623 918.429L523.623 918.429z" p-id="1990"/><path fill="#8a8a8a" d="M756.081 1017.218 291.154 1017.218c-71.121 0-128.982-58.342-128.982-130.054L162.172 136.836c0-71.712 57.861-130.054 128.982-130.054l464.928 0c71.122 0 128.984 58.342 128.984 130.054l0 750.328C885.066 958.876 827.204 1017.218 756.081 1017.218zM291.154 16.783c-65.607 0-118.982 53.856-118.982 120.054l0 750.328c0 66.198 53.375 120.054 118.982 120.054l464.927 0c65.608 0 118.985-53.855 118.985-120.054L875.066 136.836c0-66.198-53.376-120.054-118.984-120.054L291.154 16.782zM756.082 954.69 291.154 954.69c-36.939 0-66.991-30.292-66.991-67.526l0-99.766 598.899 0 0.001 99.766C823.063 924.398 793.016 954.69 756.082 954.69zM234.163 797.398l0 89.766c0 31.72 25.566 57.526 56.991 57.526l464.928 0c31.419 0 56.98-25.807 56.98-57.526l0-89.766L234.163 797.398zM523.623 923.429c-28.387 0-51.482-23.28-51.482-51.896s23.096-51.895 51.482-51.895c28.385 0 51.477 23.279 51.477 51.895S552.008 923.429 523.623 923.429zM523.623 829.639c-22.873 0-41.482 18.794-41.482 41.895 0 23.102 18.609 41.896 41.482 41.896 22.871 0 41.477-18.794 41.477-41.896C565.1 848.433 546.494 829.639 523.623 829.639zM823.062 734.872 224.163 734.872 224.163 225.63l598.899 0L823.062 734.872zM234.163 724.872l578.899 0L813.062 235.63 234.163 235.63 234.163 724.872zM823.062 173.104 224.163 173.104l0-36.268c0-37.234 30.052-67.526 66.991-67.526l464.927 0c36.934 0 66.98 30.292 66.98 67.526L823.061 173.104zM234.163 163.104l578.899 0 0-26.268c0-31.72-25.562-57.526-56.98-57.526L291.154 79.31c-31.425 0-56.991 25.806-56.991 57.526L234.163 163.104z" p-id="1991"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/qiniu.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/qiniu.svg new file mode 100644 index 0000000..c2f9f8b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/qiniu.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="1276" t="1546225865881" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M892.928 499.712c-45.056-45.056-116.736-45.056-161.792 0-36.864 36.864-43.008 92.16-20.48 135.168L602.112 743.424c-51.2 51.2-137.216 45.056-194.56-10.24s-61.44-143.36-10.24-194.56L522.24 413.696l-45.056-45.056-124.928 124.928c-75.776 75.776-71.68 204.8 10.24 286.72 43.008 43.008 98.304 65.536 153.6 65.536 49.152 0 96.256-18.432 133.12-53.248L757.76 684.032c16.384 8.192 34.816 14.336 55.296 14.336 28.672 0 59.392-10.24 79.872-32.768 45.056-49.152 45.056-122.88 0-165.888zM847.872 614.4c-18.432 18.432-51.2 18.432-69.632 0-18.432-18.432-18.432-51.2 0-69.632 10.24-10.24 22.528-14.336 34.816-14.336s24.576 4.096 34.816 14.336c18.432 18.432 18.432 51.2 0 69.632z" p-id="1277"/><path fill="#bfbfbf" d="M296.96 372.736l108.544-108.544c51.2-51.2 137.216-45.056 194.56 10.24 26.624 26.624 43.008 63.488 45.056 100.352 2.048 36.864-10.24 69.632-34.816 94.208L485.376 593.92l45.056 45.056L655.36 514.048c36.864-36.864 55.296-88.064 53.248-141.312-2.048-53.248-24.576-104.448-63.488-143.36-81.92-81.92-208.896-86.016-286.72-10.24L249.856 327.68c-43.008-22.528-98.304-16.384-135.168 20.48-45.056 45.056-45.056 116.736 0 161.792 22.528 22.528 51.2 32.768 79.872 32.768s59.392-10.24 79.872-32.768c38.912-38.912 45.056-94.208 22.528-137.216z m-65.536 90.112c-18.432 18.432-51.2 18.432-69.632 0-18.432-18.432-18.432-51.2 0-69.632 10.24-10.24 22.528-14.336 34.816-14.336 12.288 0 24.576 4.096 34.816 14.336 18.432 18.432 18.432 49.152 0 69.632z" p-id="1278"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/redis.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/redis.svg new file mode 100644 index 0000000..bef111b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/redis.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1547360607827" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6287" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M900.512 388.751V287.87L512.708 63.967 124.904 287.87v240.093c-23.42 6.798-40.924 27.562-40.924 53.144s17.504 46.346 40.924 53.144v101.424l387.804 223.862 387.804-223.862V494.761c23.13-6.979 40.345-27.642 40.345-52.984 0-25.376-17.215-46.047-40.345-53.026zM114.87 581.107c0-13.999 11.356-25.355 25.355-25.355 13.958 0 25.314 11.356 25.314 25.355s-11.356 25.355-25.314 25.355c-13.999 0-25.355-11.356-25.355-25.355z m754.753 136.729L512.708 923.858 155.793 717.836v-83.638c23.265-6.883 40.635-27.603 40.635-53.09 0-25.487-17.37-46.207-40.635-53.09V305.709L512.708 99.646l356.915 206.063v82.856c-23.585 6.692-41.254 27.513-41.254 53.212 0 25.665 17.669 46.48 41.254 53.17v222.889z m14.99-250.745c-13.999 0-25.355-11.356-25.355-25.314 0-13.999 11.356-25.355 25.355-25.355s25.355 11.356 25.355 25.355c0 13.958-11.356 25.314-25.355 25.314z m-184.631-117.32c-5.947-2.271-12.678-0.661-17.014 4.047L511.841 542.29 338.029 357.576c-4.295-4.666-10.985-6.153-16.931-3.758a15.428 15.428 0 0 0-9.746 14.329v315.867h30.889V407.089l158.574 168.526a15.404 15.404 0 0 0 11.232 4.873c3.469-0.289 8.507-1.9 11.439-5.079l155.477-171.251v279.817h30.889v-319.79a15.492 15.492 0 0 0-9.87-14.414z" fill="#bfbfbf" p-id="6288"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/role.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/role.svg new file mode 100644 index 0000000..76cb18f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/role.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="2866" t="1543477186503" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css">@font-face{font-family:rbicon;src:url(chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2) format("woff2");font-weight:400;font-style:normal}</style></defs><path d="M609.093716 908.277839c0-106.125689 85.803749-191.929438 191.929438-191.929438 38.950386 0 75.07828 11.854465 105.561191 31.611907l0-3.38699c0-60.965821-71.69129-136.044101-128.705623-145.076075l76.771775-127.012128-178.945976 0c32.176406-46.288864 53.627343-107.254686 53.627343-174.994487 0-5.080485 0-10.725469 0-15.805954 69.433297-12.418964 114.593164-32.176406 114.593164-51.933848 0-21.450937-50.240353-41.208379-127.012128-53.627343C712.961411 158.059537 661.592062 11.289967 600.62624 11.289967c-27.095921 0-48.546858 14.112459-62.659316 35.563396 0 10.725469-10.725469 21.450937-24.837927 21.450937-12.418964 0-23.144432-9.031974-24.837927-19.757442C475.307607 27.660419 452.163175 11.289967 425.631753 11.289967 366.359427 11.289967 311.038589 145.640573 298.619625 179.510474 232.573319 191.929438 189.671444 209.993385 189.671444 231.444322c0 21.450937 44.595369 39.514884 114.593164 51.933848 0 5.080485 0 10.725469 0 15.805954 0 67.739802 19.757442 128.705623 53.627343 174.994487L178.945976 474.178611l76.771775 125.318633c-57.014333 0-132.092613 78.46527-132.092613 146.76957l1.693495 205.477398c0 33.869901 26.531422 60.965821 60.965821 60.965821l453.85667 0C620.383682 982.227122 609.093716 946.663727 609.093716 908.277839zM468.533627 962.46968l-28.789416 0-53.627343-395.148842 112.335171 98.222712L468.533627 962.46968zM498.45204 351.117971c-7.338479 62.659316-39.514884 76.771775-57.014333 76.771775-42.901874 0-55.320838-57.014333-57.014333-76.771775l-14.112459 0L370.310915 338.699008l0-12.418964 107.254686 0L477.565601 338.699008l71.69129 0 0-12.418964 107.254686 0L656.511577 338.699008l3.38699 0 0 12.418964-14.112459 0c0 0-9.031974 76.771775-57.014333 76.771775C539.660419 427.889746 530.628445 351.117971 530.628445 351.117971L498.45204 351.117971zM562.804851 962.46968l-30.482911-296.92613 112.335171-99.916207-53.627343 396.842337L562.804851 962.46968z" p-id="2867"/><path d="M918.438809 907.148842c0 1.693495-1.128997 2.822492-2.822492 2.822492l-97.658214 0 0 97.658214c0 1.693495-1.128997 2.822492-2.822492 2.822492l-43.466373 0c-1.693495 0-2.822492-1.128997-2.822492-2.822492l0-97.658214-97.658214 0c-1.693495 0-2.822492-1.128997-2.822492-2.822492L668.366042 863.68247c0-1.693495 1.128997-2.822492 2.822492-2.822492l97.658214 0 0-97.658214c0-1.693495 1.128997-2.822492 2.822492-2.822492l43.466373 0c1.693495 0 2.822492 1.128997 2.822492 2.822492l0 97.658214 97.658214 0c1.693495 0 2.822492 1.128997 2.822492 2.822492L918.438809 907.148842z" p-id="2868"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/search.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/search.svg new file mode 100644 index 0000000..84233dd --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/search.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M124.884 109.812L94.256 79.166c-.357-.357-.757-.629-1.129-.914a50.366 50.366 0 0 0 8.186-27.59C101.327 22.689 78.656 0 50.67 0 22.685 0 0 22.688 0 50.663c0 27.989 22.685 50.663 50.656 50.663 10.186 0 19.643-3.03 27.6-8.201.286.385.557.771.9 1.114l30.628 30.632a10.633 10.633 0 0 0 7.543 3.129c2.728 0 5.457-1.043 7.543-3.115 4.171-4.157 4.171-10.915.014-15.073M50.671 85.338C31.557 85.338 16 69.78 16 50.663c0-19.102 15.557-34.661 34.67-34.661 19.115 0 34.657 15.559 34.657 34.675 0 19.102-15.557 34.661-34.656 34.661"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/server.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/server.svg new file mode 100644 index 0000000..db6dcdf --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/server.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1574576420335" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9530" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M915.94 827.89h-91.42a12.5 12.5 0 0 1 0-25h78.92v-535h-78.92a12.5 12.5 0 1 1 0-25h91.42a12.5 12.5 0 0 1 12.5 12.5v560a12.5 12.5 0 0 1-12.5 12.5z" fill="#cdcdcd" p-id="9531"></path><path d="M915.94 547.91h-91.42a12.5 12.5 0 0 1 0-25h91.42a12.5 12.5 0 0 1 0 25z" fill="#cdcdcd" p-id="9532"></path><path d="M774.6 231.51a90.63 90.63 0 0 1-90.37 90.37H215.94a90.62 90.62 0 0 1-81.18-50.81 88.92 88.92 0 0 0 15.4 1.33h468.29a90.26 90.26 0 0 0 81.18-129.92c42.44 7.35 74.97 44.57 74.97 89.03z" fill="#cdcdcd" p-id="9533"></path><path d="M684.23 334.38H215.94a102.23 102.23 0 0 1-55.12-16.11 103.66 103.66 0 0 1-37.28-41.69 12.5 12.5 0 0 1 13.38-17.82 76.71 76.71 0 0 0 13.24 1.14h468.29a77.76 77.76 0 0 0 70-111.91 12.5 12.5 0 0 1 13.35-17.83 103.18 103.18 0 0 1 85.3 101.35 103.13 103.13 0 0 1-102.87 102.87zM159.46 284.9a78.31 78.31 0 0 0 56.48 24.48h468.29a77.75 77.75 0 0 0 59.28-128.2 78.73 78.73 0 0 0-24.14-19.08 103.06 103.06 0 0 1-100.92 122.8z" fill="#cdcdcd" p-id="9534"></path><path d="M618.45 284.91H150.16a102.86 102.86 0 1 1 0-205.73h468.29a102.86 102.86 0 0 1 0 205.73zM150.16 104.18a77.86 77.86 0 1 0 0 155.73h468.29a77.86 77.86 0 0 0 0-155.73z" fill="#cdcdcd" p-id="9535"></path><path d="M176.2 235.43A53.39 53.39 0 1 1 229.59 182a53.45 53.45 0 0 1-53.39 53.43z m0-81.78A28.39 28.39 0 1 0 204.59 182a28.43 28.43 0 0 0-28.39-28.35zM551.12 194.54H423a12.5 12.5 0 0 1 0-25h128.12a12.5 12.5 0 0 1 0 25z" fill="#cdcdcd" p-id="9536"></path><path d="M774.6 534.74a90.63 90.63 0 0 1-90.37 90.37H215.94a90.62 90.62 0 0 1-81.18-50.81 88.92 88.92 0 0 0 15.4 1.33h468.29a90.26 90.26 0 0 0 81.18-129.92c42.44 7.35 74.97 44.57 74.97 89.03z" fill="#cdcdcd" p-id="9537"></path><path d="M684.23 637.61H215.94a102.23 102.23 0 0 1-55.12-16.11 103.66 103.66 0 0 1-37.28-41.69A12.5 12.5 0 0 1 136.92 562a76.71 76.71 0 0 0 13.24 1.14h468.29a77.76 77.76 0 0 0 70-111.91 12.5 12.5 0 0 1 13.35-17.83 103.18 103.18 0 0 1 85.3 101.34 103.13 103.13 0 0 1-102.87 102.87z m-524.77-49.48a78.31 78.31 0 0 0 56.48 24.48h468.29a77.75 77.75 0 0 0 59.28-128.2 78.73 78.73 0 0 0-24.14-19.08 103.06 103.06 0 0 1-100.92 122.8z" fill="#cdcdcd" p-id="9538"></path><path d="M618.45 588.13H150.16a102.86 102.86 0 1 1 0-205.73h468.29a102.86 102.86 0 0 1 0 205.73zM150.16 407.4a77.86 77.86 0 1 0 0 155.73h468.29a77.86 77.86 0 0 0 0-155.73z" fill="#cdcdcd" p-id="9539"></path><path d="M176.2 538.66a53.39 53.39 0 1 1 53.39-53.39 53.45 53.45 0 0 1-53.39 53.39z m0-81.78a28.39 28.39 0 1 0 28.39 28.39 28.43 28.43 0 0 0-28.39-28.39zM551.12 497.77H423a12.5 12.5 0 0 1 0-25h128.12a12.5 12.5 0 0 1 0 25z" fill="#cdcdcd" p-id="9540"></path><path d="M774.6 869.33a90.63 90.63 0 0 1-90.37 90.37H215.94a90.62 90.62 0 0 1-81.18-50.81 88.92 88.92 0 0 0 15.4 1.33h468.29a90.26 90.26 0 0 0 81.18-129.92c42.44 7.35 74.97 44.57 74.97 89.03z" fill="#cdcdcd" p-id="9541"></path><path d="M684.23 972.2H215.94a102.23 102.23 0 0 1-55.12-16.11 103.66 103.66 0 0 1-37.28-41.69 12.5 12.5 0 0 1 13.38-17.82 76.71 76.71 0 0 0 13.24 1.14h468.29a77.76 77.76 0 0 0 70-111.91A12.5 12.5 0 0 1 701.76 768a102.73 102.73 0 0 1 55.14 174 102.16 102.16 0 0 1-72.67 30.2z m-524.77-49.48a78.31 78.31 0 0 0 56.48 24.48h468.29A77.75 77.75 0 0 0 743.51 819a78.71 78.71 0 0 0-24.14-19.08 103.06 103.06 0 0 1-100.92 122.8z" fill="#cdcdcd" p-id="9542"></path><path d="M618.45 922.72H150.16a102.86 102.86 0 1 1 0-205.73h468.29a102.86 102.86 0 0 1 0 205.73zM150.16 742a77.86 77.86 0 1 0 0 155.73h468.29a77.86 77.86 0 1 0 0-155.73z" fill="#cdcdcd" p-id="9543"></path><path d="M176.2 873.25a53.39 53.39 0 1 1 53.39-53.39 53.45 53.45 0 0 1-53.39 53.39z m0-81.78a28.39 28.39 0 1 0 28.39 28.39 28.42 28.42 0 0 0-28.39-28.4zM551.12 832.35H423a12.5 12.5 0 0 1 0-25h128.12a12.5 12.5 0 0 1 0 25z" fill="#cdcdcd" p-id="9544"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/shopping.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/shopping.svg new file mode 100644 index 0000000..87513e7 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/shopping.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M42.913 101.36c1.642 0 3.198.332 4.667.996a12.28 12.28 0 0 1 3.89 2.772c1.123 1.184 1.987 2.582 2.592 4.193.605 1.612.908 3.318.908 5.118 0 1.8-.303 3.507-.908 5.118-.605 1.611-1.469 3.01-2.593 4.194a13.3 13.3 0 0 1-3.889 2.843 10.582 10.582 0 0 1-4.667 1.066c-1.729 0-3.306-.355-4.732-1.066a13.604 13.604 0 0 1-3.825-2.843c-1.123-1.185-1.988-2.583-2.593-4.194a14.437 14.437 0 0 1-.907-5.118c0-1.8.302-3.506.907-5.118.605-1.61 1.47-3.009 2.593-4.193a12.515 12.515 0 0 1 3.825-2.772c1.426-.664 3.003-.996 4.732-.996zm53.932.285c1.643 0 3.22.331 4.733.995a11.386 11.386 0 0 1 3.889 2.772c1.08 1.185 1.945 2.583 2.593 4.194.648 1.61.972 3.317.972 5.118 0 1.8-.324 3.506-.972 5.117-.648 1.611-1.513 3.01-2.593 4.194a12.253 12.253 0 0 1-3.89 2.843 11 11 0 0 1-4.732 1.066 10.58 10.58 0 0 1-4.667-1.066 12.478 12.478 0 0 1-3.824-2.843c-1.08-1.185-1.945-2.583-2.593-4.194a13.581 13.581 0 0 1-.973-5.117c0-1.801.325-3.507.973-5.118.648-1.611 1.512-3.01 2.593-4.194a11.559 11.559 0 0 1 3.824-2.772 11.212 11.212 0 0 1 4.667-.995zm21.781-80.747c2.42 0 4.3.355 5.64 1.066 1.34.71 2.29 1.587 2.852 2.63a6.427 6.427 0 0 1 .778 3.34c-.044 1.185-.195 2.204-.454 3.057-.26.853-.8 2.606-1.62 5.26a589.268 589.268 0 0 1-2.788 8.743 1236.373 1236.373 0 0 0-3.047 9.453c-.994 3.128-1.75 5.592-2.269 7.393-1.123 3.79-2.55 6.42-4.278 7.89-1.728 1.469-3.846 2.203-6.352 2.203H39.023l1.945 12.795h65.342c4.148 0 6.223 1.943 6.223 5.828 0 1.896-.41 3.53-1.232 4.905-.821 1.374-2.442 2.061-4.862 2.061H38.505c-1.729 0-3.176-.426-4.343-1.28-1.167-.852-2.14-1.966-2.917-3.34a21.277 21.277 0 0 1-1.88-4.478 44.128 44.128 0 0 1-1.102-4.55c-.087-.568-.324-1.942-.713-4.122-.39-2.18-.865-4.904-1.426-8.174l-1.88-10.947c-.692-4.027-1.383-8.079-2.075-12.154-1.642-9.572-3.5-20.234-5.574-31.986H6.87c-1.296 0-2.377-.356-3.24-1.067a9.024 9.024 0 0 1-2.14-2.558 10.416 10.416 0 0 1-1.167-3.2C.108 8.53 0 7.488 0 6.54c0-1.896.583-3.46 1.75-4.69C2.917.615 4.494 0 6.482 0h13.095c1.728 0 3.111.284 4.148.853 1.037.569 1.858 1.28 2.463 2.132a8.548 8.548 0 0 1 1.297 2.701c.26.948.475 1.754.648 2.417.173.758.346 1.825.519 3.199.173 1.374.345 2.772.518 4.193.26 1.706.519 3.507.778 5.403h88.678z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/size.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/size.svg new file mode 100644 index 0000000..ddb25b8 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/size.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h54.796v18.286H36.531V128H18.265V73.143H0V54.857zm127.857-36.571H91.935V128H72.456V18.286H36.534V0h91.326l-.003 18.286z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/skill.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/skill.svg new file mode 100644 index 0000000..a3b7312 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/skill.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M31.652 93.206h33.401c1.44 2.418 3.077 4.663 4.93 6.692h-38.33v-6.692zm0-10.586h28.914a44.8 44.8 0 0 1-1.264-6.688h-27.65v6.688zm0-17.27H59.39c.288-2.286.714-4.532 1.34-6.687H31.65v6.687h.003zm53.913 44.84v5.85c0 2.798-2.095 5.075-4.667 5.075h-70.07c-2.576 0-4.663-2.277-4.663-5.075V31.26l23.22-20.96v22.25H17.16v6.688h18.39V6.688h45.348c2.576 0 4.667 2.277 4.667 5.066v20.009c1.987-.675 4.053-1.128 6.17-1.445v-18.56C91.738 5.28 86.874 0 80.902 0H31.15L0 28.118v87.917c0 6.48 4.859 11.759 10.832 11.759h70.07c5.974 0 10.837-5.27 10.837-11.759v-4.41c-2.117-.312-4.183-.765-6.17-1.435h-.004zM23.279 58.667h-7.96v6.688h7.96v-6.688zm-7.956 41.23h7.96v-6.691h-7.96v6.692zm7.956-23.96h-7.96v6.687h7.96v-6.688zm89.718-15.042l-4.896-4.07-12.447 17.613-11.19-9.305-3.762 5.311 16.091 13.38 16.204-22.929zM128 70.978c0-18.632-13.97-33.782-31.147-33.782-17.168 0-31.135 15.155-31.135 33.782 0 18.628 13.97 33.783 31.135 33.783 17.172 0 31.143-15.15 31.143-33.783H128zm-6.17 0c0 14.933-11.203 27.1-24.981 27.1-13.77 0-24.987-12.158-24.987-27.1 0-14.941 11.195-27.099 24.987-27.099 13.778 0 24.982 12.158 24.982 27.1z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/source.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/source.svg new file mode 100644 index 0000000..1c3a038 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/source.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1574679314986" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2155" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M546.26 538.81v257.63c0 18.38-14.9 33.29-33.29 33.29-18.01 0.37-32.91-13.93-33.29-31.94-0.01-0.45-0.01-0.9 0-1.35V538.81l-233-134.47c-15.73-9.25-21.07-29.45-11.98-45.27 8.82-15.71 28.7-21.3 44.41-12.48 0.29 0.16 0.57 0.33 0.86 0.5l233 133.14 231-133.14c15.43-9.29 35.48-4.31 44.77 11.13 0.17 0.28 0.34 0.57 0.5 0.86 9.09 15.82 3.74 36.01-11.98 45.27l-231 133.14v1.32z" fill="#515151" p-id="2156"></path><path d="M512 1006.74c-18.08 0-36.14-4.65-52.27-13.96L121.77 797.65c-32.24-18.61-52.27-53.3-52.27-90.53V316.87c0-37.23 20.03-71.92 52.27-90.53L459.73 31.22c32.24-18.61 72.29-18.61 104.53 0l337.97 195.13c32.24 18.61 52.27 53.3 52.27 90.53v390.25c0 37.23-20.03 71.92-52.27 90.53L564.27 992.78c-16.12 9.3-34.2 13.96-52.27 13.96z m0-940.77c-9.65 0-19.29 2.48-27.9 7.45L146.13 268.55c-17.21 9.94-27.9 28.45-27.9 48.32v390.25c0 19.87 10.69 38.39 27.9 48.32L484.1 950.57c17.21 9.94 38.59 9.93 55.8 0l337.97-195.13c17.21-9.94 27.9-28.45 27.9-48.32V316.87c0-19.87-10.69-38.39-27.9-48.32L539.9 73.43a55.757 55.757 0 0 0-27.9-7.46z" fill="#515151" p-id="2157"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/sqlMonitor.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/sqlMonitor.svg new file mode 100644 index 0000000..950a430 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/sqlMonitor.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="6696" t="1544607518503" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path d="M896 716.8c-44.8 0-76.8 25.6-96 57.6L460.8 614.4l147.2-243.2c25.6 12.8 51.2 25.6 83.2 25.6 83.2 0 153.6-70.4 153.6-153.6s-70.4-153.6-153.6-153.6-153.6 64-153.6 147.2c0 19.2 6.4 38.4 12.8 57.6L300.8 403.2c-25.6-44.8-76.8-76.8-134.4-76.8C83.2 326.4 12.8 396.8 12.8 480c0 83.2 70.4 153.6 153.6 153.6 12.8 0 19.2 0 32-6.4l57.6 128c-12.8 12.8-19.2 25.6-19.2 44.8 0 38.4 32 64 64 64 38.4 0 64-32 64-64 0-12.8-6.4-19.2-6.4-32l70.4-121.6 352 166.4v6.4c0 64 51.2 115.2 115.2 115.2s115.2-51.2 115.2-115.2-51.2-102.4-115.2-102.4z m-204.8-582.4c57.6 0 108.8 44.8 108.8 108.8s-44.8 108.8-108.8 108.8-108.8-57.6-108.8-115.2 51.2-102.4 108.8-102.4zM569.6 332.8l-153.6 256-108.8-44.8c6.4-19.2 12.8-44.8 12.8-64V448l249.6-115.2zM64 480c0-57.6 44.8-108.8 108.8-108.8s108.8 44.8 108.8 108.8c0 57.6-44.8 108.8-108.8 108.8S64 537.6 64 480z m262.4 262.4c-6.4 0-12.8-6.4-19.2-6.4h-6.4l-57.6-128c12.8-6.4 25.6-12.8 38.4-25.6l108.8 51.2-64 108.8z m569.6 147.2c-38.4 0-64-32-64-64 0-38.4 32-64 64-64s64 32 64 64c0 38.4-25.6 64-64 64z" p-id="6697"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/swagger.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/swagger.svg new file mode 100644 index 0000000..ded7de8 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/swagger.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="3388" t="1553861152984" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M306.689473 349.006765l408.370805-0.3776c22.463618 0 40.678468-18.213827 40.678468-40.678468 0-22.463618-18.21485-40.677445-40.678468-40.677445l-408.370805 0.3776c-22.465664 0-40.679491 18.203594-40.679491 40.678468C266.009981 330.792938 284.223808 349.006765 306.689473 349.006765z" p-id="3389"/><path fill="#bfbfbf" d="M306.689473 511.719614l408.370805-0.3776c22.463618 0 40.678468-18.213827 40.678468-40.677445 0-22.463618-18.21485-40.677445-40.678468-40.677445l-408.370805 0.3776c-22.465664 0-40.679491 18.202571-40.679491 40.677445C266.009981 493.505787 284.223808 511.719614 306.689473 511.719614z" p-id="3390"/><path fill="#bfbfbf" d="M877.157095 624.190175l-0.337691-482.536968c-1.905396-43.141566-37.141922-77.602426-80.721463-77.751828l-573.366649 0.327458c-43.220361 1.917676-77.763085 37.302581-77.763085 80.999802l0 43.220361-0.335644 0 0.277316 645.76761 0.058328 0 0 43.220361c0 44.928259 36.428677 81.354889 81.357959 81.354889l40.677445 0 0 0.229221 120.088052-0.217964c22.465664 0 40.679491-18.213827 40.679491-40.677445 0-22.465664-18.213827-40.679491-40.679491-40.679491l-104.773252 0.189312c-39.148625-3.783163-53.509704-17.011442-56.051597-58.137095l-0.278339-623.272269 0.23843 32.224935c-0.972141-69.328995 14.937201-81.882915 80.204693-82.804914l-9.414417-0.099261 419.393859-0.23843c60.562331 1.429559 78.277808 12.652158 79.114872 70.174246l0 3.744277c0 2.99931 0 5.998621-0.081864 9.245572l0.081864-4.080945 0.25685 367.961466-160.131047 0.217964 0 0.11768-43.220361 0c-44.928259 0-81.354889 36.418444-81.354889 81.357959l0 40.677445-0.278339 0 0.257873 195.506742c-2.62171 12.93152 1.033539 26.874067 11.062963 36.903491 4.031826 4.030803 8.721639 7.021927 13.68672 9.006118 4.90573 2.087545 10.287297 3.25002 15.927761 3.25002 14.20349 0 26.656103-7.290033 33.924647-18.304901l271.679609-272.363178c3.01773-1.826602 5.838985-3.932566 8.303106-6.463202 7.704472-7.398504 12.532431-17.749246 12.532431-29.278837C878.171192 629.950366 877.793592 627.031896 877.157095 624.190175zM592.290139 819.2395l-0.078795-67.76129c0.556679-61.910025 14.896268-77.462233 82.549088-77.462233l-82.071204 0.545422-0.497327 73.223698-0.099261-73.79982 145.274688-0.197498L592.290139 819.2395z" p-id="3391"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/sys-tools.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/sys-tools.svg new file mode 100644 index 0000000..8f9055e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/sys-tools.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1649727419510" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18534" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M375.36 32v224c0 32-196.16 32-196.16 0V32a245.12 245.12 0 0 0 20.8 457.28L132.16 800a151.04 151.04 0 0 0 0 64 148.48 148.48 0 1 0 289.92-64l-67.84-311.36A245.12 245.12 0 0 0 375.36 32zM277.44 896a68.16 68.16 0 1 1 68.16-68.16A68.16 68.16 0 0 1 277.44 896zM864 544V288l48.96-73.28a51.84 51.84 0 0 0 5.12-48L877.12 64a51.84 51.84 0 0 0-48-32H771.2a51.84 51.84 0 0 0-48 32l-40.96 102.72a51.84 51.84 0 0 0 5.12 48L736 288v256a128 128 0 0 0-128 128v192a128 128 0 0 0 128 128h128a128 128 0 0 0 128-128v-192a128 128 0 0 0-128-128z" fill="#bfbfbf" p-id="18535"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/system.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/system.svg new file mode 100644 index 0000000..9333c60 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/system.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.719" height="200" class="icon" p-id="10233" t="1543827724451" version="1.1" viewBox="0 0 1084 1024"><defs><style type="text/css">@font-face{font-family:rbicon;src:url(chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2) format("woff2");font-weight:400;font-style:normal}</style></defs><path fill="#bfbfbf" d="M1080.09609 434.500756c-4.216302-23.731757-26.9241-47.945376-50.595623-53.185637l-17.648235-4.095836a175.940257 175.940257 0 0 1-101.612877-80.832531 177.807476 177.807476 0 0 1-18.732427-129.801867l5.541425-16.684509c7.10748-23.129428-2.108151-54.992624-20.599646-70.833873 0 0-16.624276-14.094495-63.244529-41.199293-46.800951-26.984332-66.858502-34.513443-66.858502-34.513443-22.76803-8.372371-54.631227-0.361397-71.255503 17.407304l-12.287509 13.251234a173.470708 173.470708 0 0 1-120.465769 48.065842A174.13327 174.13327 0 0 1 421.329029 33.590675L409.583617 20.761071C393.140039 2.99237 361.096144-4.898138 338.267881 3.353767c0 0-20.358715 7.529111-67.099434 34.513443-46.800951 27.34573-63.244529 41.440225-63.244529 41.440225-18.431263 15.66055-27.646894 47.222582-20.539413 70.592941l5.059562 16.865207a178.048407 178.048407 0 0 1-18.672194 129.621169 174.916297 174.916297 0 0 1-102.275439 81.073463l-17.045906 3.854904c-23.310126 5.42096-46.258856 29.333415-50.595623 53.185637 0 0-3.854905 21.382674-3.854905 75.712737 0 54.330062 3.854905 75.712736 3.854905 75.712736 4.216302 23.972688 26.9241 47.945376 50.595623 53.185637l16.624276 3.854905a174.253736 174.253736 0 0 1 102.395904 81.314394c23.310126 40.837896 28.911785 87.337683 18.732427 129.801867l-4.81863 16.443578c-7.10748 23.129428 2.108151 54.992624 20.599646 70.833872 0 0 16.624276 14.094495 63.244529 41.199293 46.800951 27.104798 66.918735 34.513443 66.918735 34.513443 22.707798 8.372371 54.631227 0.361397 71.255503-17.407303l11.624947-12.588673a175.096996 175.096996 0 0 1 242.256662 0.120465l11.624947 12.648906c16.383345 17.708468 48.427239 25.598976 71.255503 17.347071 0 0 20.358715-7.529111 67.159666-34.513443 46.740719-27.104798 63.124063-41.199293 63.124064-41.199293 18.491496-15.600317 27.707127-47.463513 20.599646-70.833873l-5.059562-17.106139a176.723284 176.723284 0 0 1 18.672194-129.139305 176.060722 176.060722 0 0 1 102.395904-81.314394l16.68451-3.854905c23.310126-5.42096 46.258856-29.333415 50.595623-53.185637 0 0 3.854905-21.382674 3.854904-75.712737-0.240932-54.330062-4.095836-75.833202-4.095836-75.833202z m-537.819428 293.334149c-119.261112 0-216.175824-97.336342-216.175824-217.621412a216.657687 216.657687 0 0 1 216.236057-217.320249c119.200879 0 216.115591 97.276109 216.11559 217.56118-0.240932 120.044139-96.974945 217.320248-216.175823 217.320249z" p-id="10234"/></svg> diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/system1.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/system1.svg new file mode 100644 index 0000000..37b0a0a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/system1.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588584086939" class="icon" viewBox="0 0 1084 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1156" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css"></style></defs><path d="M1080.096 434.5c-4.216-23.731-26.924-47.945-50.596-53.185l-17.648-4.096a175.94 175.94 0 0 1-101.613-80.832 177.807 177.807 0 0 1-18.732-129.802l5.541-16.685c7.108-23.13-2.108-54.992-20.6-70.833 0 0-16.624-14.095-63.244-41.2-46.8-26.984-66.858-34.513-66.858-34.513-22.768-8.373-54.632-0.362-71.256 17.407l-12.287 13.251a173.47 173.47 0 0 1-120.466 48.066 174.133 174.133 0 0 1-121.008-48.487l-11.745-12.83C393.14 2.992 361.096-4.899 338.268 3.354c0 0-20.359 7.529-67.1 34.513-46.8 27.346-63.244 41.44-63.244 41.44-18.431 15.661-27.647 47.223-20.54 70.593l5.06 16.866a178.048 178.048 0 0 1-18.672 129.62A174.916 174.916 0 0 1 71.496 377.46l-17.045 3.855c-23.31 5.421-46.26 29.334-50.596 53.186 0 0-3.855 21.382-3.855 75.712s3.855 75.713 3.855 75.713C8.07 609.9 30.779 633.872 54.45 639.112l16.624 3.855A174.254 174.254 0 0 1 173.47 724.28c23.31 40.838 28.911 87.338 18.732 129.802l-4.818 16.444c-7.108 23.129 2.108 54.992 20.6 70.833 0 0 16.623 14.095 63.244 41.2 46.8 27.105 66.918 34.513 66.918 34.513 22.708 8.373 54.632 0.362 71.256-17.407l11.625-12.589a175.097 175.097 0 0 1 242.257 0.12l11.624 12.65c16.384 17.708 48.428 25.599 71.256 17.347 0 0 20.359-7.53 67.16-34.514 46.74-27.105 63.124-41.2 63.124-41.2 18.491-15.6 27.707-47.463 20.6-70.833l-5.06-17.106A176.723 176.723 0 0 1 910.66 724.4a176.06 176.06 0 0 1 102.396-81.314l16.684-3.855c23.31-5.42 46.26-29.333 50.596-53.185 0 0 3.855-21.383 3.855-75.713-0.241-54.33-4.096-75.833-4.096-75.833z m-537.82 293.335c-119.26 0-216.175-97.336-216.175-217.622a216.658 216.658 0 0 1 216.236-217.32c119.2 0 216.115 97.276 216.115 217.561-0.24 120.045-96.974 217.32-216.175 217.32z" p-id="1157"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tab.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tab.svg new file mode 100644 index 0000000..b4b48e4 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tab.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M78.921.052H49.08c-1.865 0-3.198 1.599-3.198 3.464v6.661c0 1.865 1.6 3.464 3.198 3.464h29.84c1.865 0 3.198-1.599 3.198-3.464V3.516C82.385 1.65 80.786.052 78.92.052zm45.563 0H94.642c-1.865 0-3.464 1.599-3.464 3.464v6.661c0 1.865 1.599 3.464 3.464 3.464h29.842c1.865-.266 3.464-1.599 3.464-3.464V3.516c0-1.865-1.599-3.464-3.464-3.464zm0 22.382H40.02c-1.866 0-3.464-1.599-3.464-3.464V3.516c0-1.865-1.599-3.464-3.464-3.464H3.516C1.65.052.052 1.651.052 3.516V124.75c0 1.598 1.599 3.197 3.464 3.197h120.968c1.865 0 3.464-1.599 3.464-3.464V25.898c0-1.865-1.599-3.464-3.464-3.464z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/theme.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/theme.svg new file mode 100644 index 0000000..5982a2f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/theme.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M125.5 36.984L95.336 2.83C93.735 1.018 91.565 0 89.3 0c-2.263 0-4.433 1.018-6.033 2.83l-3.786 4.286c-1.6 1.812-3.77 2.83-6.032 2.831H54.553c-2.263 0-4.434-1.018-6.033-2.83L44.734 2.83C43.134 1.018 40.964 0 38.701 0c-2.263 0-4.434 1.018-6.034 2.83L2.5 36.984C.9 38.796 0 41.254 0 43.815c0 2.562.899 5.02 2.5 6.831L14.565 64.31c2.178 2.468 5.367 3.403 8.33 2.444 1.35-.435 2.709.592 2.709 2.18v49.407c0 5.313 3.84 9.66 8.532 9.66h59.726c4.693 0 8.532-4.347 8.532-9.66V68.934c0-1.59 1.36-2.616 2.71-2.181 2.962.96 6.15.024 8.329-2.444L125.5 50.646c1.6-1.811 2.499-4.269 2.499-6.83 0-2.563-.899-5.02-2.5-6.832z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/timing.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/timing.svg new file mode 100644 index 0000000..f8fdc6d --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/timing.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="2986" t="1546864403462" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M814.502 270.913l30.18-30.18 30.58 30.58 37.825-37.825-86.377-86.378-37.825 37.825 30.58 30.58-30.18 30.18c-66.856-61.301-154.087-100.642-250.374-106.858V66.548h-53.499v72.289c-214.046 13.792-383.407 191.652-383.407 409.199 0 226.533 183.624 410.157 410.157 410.157s410.157-183.624 410.157-410.157c-0.001-106.858-40.892-204.139-107.817-277.123zM529.994 598.26v74.606h-35.666V598.26c-20.724-7.385-35.666-26.958-35.666-50.225 0-23.267 14.942-42.842 35.666-50.225v-235.1h35.666v235.102c20.724 7.383 35.666 26.958 35.666 50.225 0 23.265-14.942 42.839-35.666 50.223z" p-id="2987"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tools.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tools.svg new file mode 100644 index 0000000..aba1a40 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tools.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.781" height="200" class="icon" p-id="1270" t="1545876582522" version="1.1" viewBox="0 0 1028 1024"><defs><style type="text/css"/></defs><path d="M20.746854 180.67456c-27.09504 27.136-21.31968 65.35168 0.26624 86.87616 0.86016 0.83968 87.49056 83.57888 209.3056 205.4144 3.13344 3.13344 7.22944 4.66944 11.32544 4.66944s8.192-1.57696 11.32544-4.66944c6.2464-6.2464 6.2464-16.384 0-22.6304-18.37056-18.37056-35.84-35.7376-52.40832-52.18304l50.85184-50.85184c6.2464-6.2464 6.2464-16.384 0-22.6304s-16.384-6.2464-22.6304 0l-50.97472 50.97472c-28.50816-28.16-53.63712-52.736-74.07616-72.66304l115.67104-115.67104c6.2464-6.2464 6.2464-16.384 0-22.6304s-16.384-6.2464-22.6304 0l-116.03968 116.03968c-23.552-22.81472-37.13024-35.77856-37.33504-36.00384-6.7584-6.7584-15.62624-25.76384 0-41.3696l160.01024-160.01024c6.18496-6.26688 22.6304-18.71872 40.67328-0.77824 0.79872 0.90112 81.59232 92.672 204.92288 216.00256 6.2464 6.2464 16.384 6.2464 22.6304 0s6.2464-16.384 0-22.6304c-122.55232-122.53184-202.752-213.6064-204.22656-215.26528-29.81888-29.75744-65.80224-20.82816-86.6304 0l-160.03072 160.01024zM699.392614 772.66944c-6.2464-6.2464-16.384-6.2464-22.6304 0l-50.91328 50.87232c-15.52384-15.70816-31.80544-32.1536-48.96768-49.31584-6.2464-6.2464-16.384-6.2464-22.6304 0s-6.2464 16.384 0 22.6304c118.53824 118.49728 201.3184 207.01184 202.50624 208.2816 10.97728 11.01824 26.0096 17.05984 42.33216 17.05984l0 0c16.7936 0 33.792-6.5536 44.31872-17.12128l159.92832-161.83296c20.13184-20.13184 21.27872-54.272 2.49856-73.1136l-214.58944-214.56896c-6.2464-6.2464-16.384-6.2464-22.6304 0s-6.2464 16.384 0 22.6304l214.58944 214.56896c6.41024 6.41024 5.18144 20.23424-2.51904 27.93472l-159.96928 161.83296c-3.6864 3.70688-12.04224 7.68-21.62688 7.68 0 0 0 0 0 0-5.50912 0-13.37344-1.35168-19.33312-7.33184-0.32768-0.34816-13.7216-14.66368-36.98688-39.0144l116.61312-116.61312c6.2464-6.2464 6.2464-16.384 0-22.6304s-16.384-6.2464-22.6304 0l-116.1216 116.1216c-19.968-20.76672-44.4416-46.01856-72.31488-74.42432l51.07712-51.07712c6.2464-6.20544 6.2464-16.32256 0-22.58944zM4.608614 1018.53184c3.072 3.13344 7.20896 4.79232 11.44832 4.79232 1.536 0 3.072-0.22528 4.56704-0.67584l320-95.3344c2.60096-0.77824 4.89472-2.1504 6.77888-4.05504l546.87744-550.56384c0.77824-0.77824 1.14688-1.76128 1.72032-2.62144l116.98176-117.00224c9.40032-9.44128 14.62272-21.95456 14.62272-35.28704 0-13.312-5.2224-25.82528-14.62272-35.20512l-167.5264-167.48544c-18.82112-18.82112-51.67104-18.82112-70.49216 0l-119.64416 119.64416c-0.77824 0.75776-1.18784 1.76128-1.76128 2.6624l-547.71712 547.7376c-1.80224 1.78176-3.13344 3.97312-3.91168 6.36928l-101.13024 310.8864c-1.86368 5.67296-0.4096 11.83744 3.74784 16.13824zM667.587174 168.67328l33.23904 33.23904-496.7424 498.0736-55.25504-12.53376 518.7584-518.77888zM224.072294 725.31968l499.42528-500.736 77.94688 77.94688-503.93088 497.47968-73.44128 0 0-74.69056zM860.365414 361.472l-519.80288 523.32544-18.47296-64.06144 501.98528-495.57504 36.29056 36.31104zM127.836774 715.48928l64.22528 14.58176 0 85.9136c0 8.82688 7.168 15.99488 15.99488 15.99488l83.968 0 20.29568 70.41024-271.60576 80.93696 87.1424-267.83744zM797.676134 37.72416c6.7584-6.7584 18.49344-6.7584 25.25184 0l167.5264 167.5264c3.35872 3.35872 5.2224 7.84384 5.2224 12.61568 0 4.73088-1.86368 9.25696-5.24288 12.63616l-107.86816 107.90912-192.73728-192.73728 107.86816-107.9296z" p-id="1271"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tree-table.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tree-table.svg new file mode 100644 index 0000000..8aafdb8 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tree-table.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M44.8 0h79.543C126.78 0 128 1.422 128 4.267v23.466c0 2.845-1.219 4.267-3.657 4.267H44.8c-2.438 0-3.657-1.422-3.657-4.267V4.267C41.143 1.422 42.362 0 44.8 0zm22.857 48h56.686c2.438 0 3.657 1.422 3.657 4.267v23.466c0 2.845-1.219 4.267-3.657 4.267H67.657C65.22 80 64 78.578 64 75.733V52.267C64 49.422 65.219 48 67.657 48zm0 48h56.686c2.438 0 3.657 1.422 3.657 4.267v23.466c0 2.845-1.219 4.267-3.657 4.267H67.657C65.22 128 64 126.578 64 123.733v-23.466C64 97.422 65.219 96 67.657 96zM50.286 68.267c2.02 0 3.657-1.91 3.657-4.267 0-2.356-1.638-4.267-3.657-4.267H17.37V32h6.4c2.02 0 3.658-1.91 3.658-4.267V4.267C27.429 1.91 25.79 0 23.77 0H3.657C1.637 0 0 1.91 0 4.267v23.466C0 30.09 1.637 32 3.657 32h6.4v80c0 2.356 1.638 4.267 3.657 4.267h36.572c2.02 0 3.657-1.91 3.657-4.267 0-2.356-1.638-4.267-3.657-4.267H17.37V68.267h32.915z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tree.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tree.svg new file mode 100644 index 0000000..dd4b7dd --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/tree.svg @@ -0,0 +1 @@ +<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M126.713 90.023c.858.985 1.287 2.134 1.287 3.447v29.553c0 1.423-.429 2.6-1.287 3.53-.858.93-1.907 1.395-3.146 1.395H97.824c-1.145 0-2.146-.465-3.004-1.395-.858-.93-1.287-2.107-1.287-3.53V93.47c0-.875.19-1.696.572-2.462.382-.766.906-1.368 1.573-1.806a3.84 3.84 0 0 1 2.146-.657h9.725V69.007a3.84 3.84 0 0 0-.43-1.806 3.569 3.569 0 0 0-1.143-1.313 2.714 2.714 0 0 0-1.573-.492h-36.47v23.149h9.725c1.144 0 2.145.492 3.004 1.478.858.985 1.287 2.134 1.287 3.447v29.553c0 .876-.191 1.696-.573 2.463-.38.766-.905 1.368-1.573 1.806a3.84 3.84 0 0 1-2.145.656H51.915a3.84 3.84 0 0 1-2.145-.656c-.668-.438-1.216-1.04-1.645-1.806a4.96 4.96 0 0 1-.644-2.463V93.47c0-1.313.43-2.462 1.288-3.447.858-.986 1.907-1.478 3.146-1.478h9.582v-23.15h-37.9c-.953 0-1.74.356-2.359 1.068-.62.711-.93 1.56-.93 2.544v19.538h9.726c1.239 0 2.264.492 3.074 1.478.81.985 1.216 2.134 1.216 3.447v29.553c0 1.423-.405 2.6-1.216 3.53-.81.93-1.835 1.395-3.074 1.395H4.29c-.476 0-.93-.082-1.358-.246a4.1 4.1 0 0 1-1.144-.657 4.658 4.658 0 0 1-.93-1.067 5.186 5.186 0 0 1-.643-1.395 5.566 5.566 0 0 1-.215-1.56V93.47c0-.437.048-.875.143-1.313a3.95 3.95 0 0 1 .429-1.15c.19-.328.429-.656.715-.984.286-.329.572-.602.858-.821.286-.22.62-.383 1.001-.493.382-.11.763-.164 1.144-.164h9.726V61.619c0-.985.31-1.833.93-2.544.619-.712 1.358-1.068 2.216-1.068h44.335V39.62h-9.582c-1.24 0-2.288-.492-3.146-1.477a5.09 5.09 0 0 1-1.287-3.448V5.14c0-1.423.429-2.627 1.287-3.612.858-.985 1.907-1.477 3.146-1.477h25.743c.763 0 1.478.246 2.145.739a5.17 5.17 0 0 1 1.573 1.888c.382.766.573 1.587.573 2.462v29.553c0 1.313-.43 2.463-1.287 3.448-.859.985-1.86 1.477-3.004 1.477h-9.725v18.389h42.762c.954 0 1.74.355 2.36 1.067.62.711.93 1.56.93 2.545v26.925h9.582c1.239 0 2.288.492 3.146 1.478z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/unlock.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/unlock.svg new file mode 100644 index 0000000..1219e41 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/unlock.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="1381" t="1545700997954" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path d="M880 512H320V288c0-106.032 85.968-192 192-192s192 85.968 192 192a48 48 0 1 0 96 0c0-159.056-128.944-288-288-288S224 128.944 224 288v224H144a48 48 0 0 0-48 48v416a48 48 0 0 0 48 48h736a48 48 0 0 0 48-48V560a48 48 0 0 0-48-48zM560 786.688V880a48 48 0 1 1-96 0v-93.312c-28.576-16.624-48-47.248-48-82.688a96 96 0 1 1 192 0c0 35.44-19.424 66.064-48 82.688z" p-id="1382"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/user.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/user.svg new file mode 100644 index 0000000..09d7a81 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/user.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="2702" t="1561614445035" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#8a8a8a" d="M914.285769 802.889143q0 68.534857-41.691429 108.251429t-110.884571 39.716571l-499.419429 0q-69.12 0-110.884571-39.716571t-41.691429-108.251429q0-30.281143 1.974857-59.172571t7.972571-62.317714 15.140571-62.025143 24.576-55.734857 35.401143-46.299429 48.859429-30.573714 63.707429-11.410286q5.12 0 23.990857 12.288t42.569143 27.428571 61.732571 27.428571 76.288 12.288 76.288-12.288 61.732571-27.428571 42.569143-27.428571 23.990857-12.288q34.889143 0 63.707429 11.410286t48.859429 30.573714 35.401143 46.299429 24.576 55.734857 15.140571 62.025143 7.972571 62.317714 1.974857 59.172571zM731.428626 292.571429q0 90.843429-64.292571 155.136t-155.136 64.292571-155.136-64.292571-64.292571-155.136 64.292571-155.136 155.136-64.292571 155.136 64.292571 64.292571 155.136z" p-id="2703"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/user1.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/user1.svg new file mode 100644 index 0000000..14ca51e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/user1.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="4263" t="1553934943780" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#8a8a8a" d="M512 256s-97.2-4.8-144-96c16.8 113.6 108 192 144 192s127.2-78.8 144-192c-46.8 91.2-144 96-144 96z" p-id="4264"/><path fill="#8a8a8a" d="M928 448C928 218.4 741.6 32 512 32S96 218.4 96 448c0 186.8 122.8 344.4 292.4 397.2-42 35.2-68.4 88-68.4 146.8h64c0-70.8 57.2-128 128-128s128 57.2 128 128h64c0-58.8-26.4-111.6-68.4-146.8 169.6-52.8 292.4-210.4 292.4-397.2z m-416 352c-194.4 0-352-157.6-352-352s157.6-352 352-352 352 157.6 352 352-157.6 352-352 352z" p-id="4265"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/validCode.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/validCode.svg new file mode 100644 index 0000000..a1feb74 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/validCode.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="1777" t="1561614261684" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#8a8a8a" d="M963.801169 218.170758a72.850542 72.850542 0 0 0-57.513586-63.903984 1357.959666 1357.959666 0 0 1-185.960594-42.815669A690.80207 690.80207 0 0 1 554.17663 14.317049a76.045741 76.045741 0 0 0-88.826539 0 435.825173 435.825173 0 0 1-167.428438 96.495016 624.341926 624.341926 0 0 1-180.848276 44.732789 67.738223 67.738223 0 0 0-56.874546 63.903984S58.281712 379.847839 58.281712 521.075644c0 255.615937 301.626806 502.924356 452.440208 502.924356s406.42934-174.457877 447.32789-499.090117c10.224637-191.711953 3.195199-306.100085 3.195199-306.100085zM799.567929 415.63407l-315.046642 297.153527a42.815669 42.815669 0 0 1-52.401267 5.112318l-8.307518-7.029438L249.993665 530.022202a42.815669 42.815669 0 0 1 63.903984-58.791666L457.042574 621.404899l283.73369-268.396734a42.815669 42.815669 0 1 1 58.791665 63.903984" p-id="1778"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/visits.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/visits.svg new file mode 100644 index 0000000..8425662 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/visits.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="4347" t="1544682770180" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path d="M320 128c0-70.656-57.344-128-128-128S64 57.344 64 128s57.344 128 128 128S320 198.656 320 128zM544 192C596.992 192 640 148.992 640 96S596.992 0 544 0 448 43.008 448 96 491.008 192 544 192zM864 64C811.008 64 768 107.008 768 160S811.008 256 864 256 960 212.992 960 160 916.992 64 864 64zM537.088 257.216C460.032 256 372.352 267.904 302.144 330.112 231.872 392.32 240.64 547.712 339.968 589.504c99.392 41.728 121.28 113.92 94.656 203.776C408 883.136 453.44 960 567.04 960 762.88 960 832 776.512 832 570.944 832 347.392 744.128 260.352 537.088 257.216z" p-id="4348"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/web.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/web.svg new file mode 100644 index 0000000..9c57415 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/web.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1572860137475" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1681" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M698.026667 597.333333C701.44 569.173333 704 541.013333 704 512 704 482.986667 701.44 454.826667 698.026667 426.666667L842.24 426.666667C849.066667 453.973333 853.333333 482.56 853.333333 512 853.333333 541.44 849.066667 570.026667 842.24 597.333333M622.506667 834.56C648.106667 787.2 667.733333 736 681.386667 682.666667L807.253333 682.666667C766.293333 753.066667 701.013333 807.68 622.506667 834.56M611.84 597.333333 412.16 597.333333C407.893333 569.173333 405.333333 541.013333 405.333333 512 405.333333 482.986667 407.893333 454.4 412.16 426.666667L611.84 426.666667C615.68 454.4 618.666667 482.986667 618.666667 512 618.666667 541.013333 615.68 569.173333 611.84 597.333333M512 851.626667C476.586667 800.426667 448 743.68 430.506667 682.666667L593.493333 682.666667C576 743.68 547.413333 800.426667 512 851.626667M341.333333 341.333333 216.746667 341.333333C257.28 270.506667 322.986667 215.893333 401.066667 189.44 375.466667 236.8 356.266667 288 341.333333 341.333333M216.746667 682.666667 341.333333 682.666667C356.266667 736 375.466667 787.2 401.066667 834.56 322.986667 807.68 257.28 753.066667 216.746667 682.666667M181.76 597.333333C174.933333 570.026667 170.666667 541.44 170.666667 512 170.666667 482.56 174.933333 453.973333 181.76 426.666667L325.973333 426.666667C322.56 454.826667 320 482.986667 320 512 320 541.013333 322.56 569.173333 325.973333 597.333333M512 171.946667C547.413333 223.146667 576 280.32 593.493333 341.333333L430.506667 341.333333C448 280.32 476.586667 223.146667 512 171.946667M807.253333 341.333333 681.386667 341.333333C667.733333 288 648.106667 236.8 622.506667 189.44 701.013333 216.32 766.293333 270.506667 807.253333 341.333333M512 85.333333C276.053333 85.333333 85.333333 277.333333 85.333333 512 85.333333 747.52 276.48 938.666667 512 938.666667 747.52 938.666667 938.666667 747.52 938.666667 512 938.666667 276.48 747.52 85.333333 512 85.333333Z" p-id="1682" fill="#515151"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/wechat.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/wechat.svg new file mode 100644 index 0000000..c586e55 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/wechat.svg @@ -0,0 +1 @@ +<svg width="128" height="110" xmlns="http://www.w3.org/2000/svg"><path d="M86.635 33.334c1.467 0 2.917.113 4.358.283C87.078 14.392 67.58.111 45.321.111 20.44.111.055 17.987.055 40.687c0 13.104 6.781 23.863 18.115 32.209l-4.527 14.352 15.82-8.364c5.666 1.182 10.207 2.395 15.858 2.395 1.42 0 2.829-.073 4.227-.189-.886-3.19-1.398-6.53-1.398-9.996 0-20.845 16.98-37.76 38.485-37.76zm-24.34-12.936c3.407 0 5.665 2.363 5.665 5.954 0 3.576-2.258 5.97-5.666 5.97-3.392 0-6.795-2.395-6.795-5.97 0-3.591 3.403-5.954 6.795-5.954zM30.616 32.323c-3.393 0-6.818-2.395-6.818-5.971 0-3.591 3.425-5.954 6.818-5.954 3.392 0 5.65 2.363 5.65 5.954 0 3.576-2.258 5.97-5.65 5.97z"/><path d="M127.945 70.52c0-19.075-18.108-34.623-38.448-34.623-21.537 0-38.5 15.548-38.5 34.623 0 19.108 16.963 34.622 38.5 34.622 4.508 0 9.058-1.2 13.584-2.395l12.414 7.167-3.404-11.923c9.087-7.184 15.854-16.712 15.854-27.471zm-50.928-5.97c-2.254 0-4.53-2.362-4.53-4.773 0-2.378 2.276-4.771 4.53-4.771 3.422 0 5.665 2.393 5.665 4.771 0 2.41-2.243 4.773-5.665 4.773zm24.897 0c-2.24 0-4.498-2.362-4.498-4.773 0-2.378 2.258-4.771 4.498-4.771 3.392 0 5.665 2.393 5.665 4.771 0 2.41-2.273 4.773-5.665 4.773z"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/weixin.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/weixin.svg new file mode 100644 index 0000000..8dbcfa5 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/weixin.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" class="icon" p-id="2023" t="1564885435527" version="1.1" viewBox="0 0 1024 1024"><defs><style type="text/css"/></defs><path fill="#bfbfbf" d="M1024 659.2c0-147.2-147.2-262.4-307.2-262.4-172.8 0-307.2 115.2-307.2 262.4 0 147.2 134.4 262.4 307.2 262.4 38.4 0 70.4-6.4 108.8-19.2l102.4 51.2L896 870.4C972.8 812.8 1024 742.4 1024 659.2zM614.4 614.4c-19.2 0-38.4-19.2-38.4-38.4 0-19.2 19.2-38.4 38.4-38.4 25.6 0 44.8 19.2 44.8 38.4C659.2 595.2 646.4 614.4 614.4 614.4zM812.8 614.4c-19.2 0-38.4-19.2-38.4-38.4 0-19.2 19.2-38.4 38.4-38.4 25.6 0 44.8 19.2 44.8 38.4C864 595.2 844.8 614.4 812.8 614.4z" p-id="2024"/><path fill="#bfbfbf" d="M364.8 128C166.4 128 0 262.4 0 435.2c0 102.4 51.2 179.2 147.2 243.2l-38.4 108.8 128-64c44.8 6.4 83.2 19.2 128 19.2 12.8 0 25.6 0 32 0C390.4 716.8 384 691.2 384 665.6c0-160 134.4-288 307.2-288 12.8 0 25.6 0 32 0C697.6 236.8 537.6 128 364.8 128zM243.2 371.2C217.6 371.2 192 352 192 326.4c0-25.6 25.6-44.8 57.6-44.8s44.8 19.2 44.8 44.8C288 352 268.8 371.2 243.2 371.2zM499.2 371.2c-25.6 0-57.6-19.2-57.6-44.8 0-25.6 25.6-44.8 57.6-44.8 25.6 0 44.8 19.2 44.8 44.8C544 352 524.8 371.2 499.2 371.2z" p-id="2025"/></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svg/zujian.svg b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/zujian.svg new file mode 100644 index 0000000..2aba32f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svg/zujian.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1574576020792" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5498" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M64 64h384v384H64V64z m0 512h384v384H64V576z m512 0h384v384H576V576z m192-128c106.039 0 192-85.961 192-192S874.039 64 768 64s-192 85.961-192 192 85.961 192 192 192z" p-id="5499" fill="#bfbfbf"></path></svg>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/assets/icons/svgo.yml b/UI source code/dns_mapping_ui-master/src/assets/icons/svgo.yml new file mode 100644 index 0000000..d11906a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/icons/svgo.yml @@ -0,0 +1,22 @@ +# replace default config + +# multipass: true +# full: true + +plugins: + + # - name + # + # or: + # - name: false + # - name: true + # + # or: + # - name: + # param1: 1 + # param2: 2 + +- removeAttrs: + attrs: + - 'fill' + - 'fill-rule' diff --git a/UI source code/dns_mapping_ui-master/src/assets/images/avatar.png b/UI source code/dns_mapping_ui-master/src/assets/images/avatar.png Binary files differnew file mode 100644 index 0000000..997732a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/images/avatar.png diff --git a/UI source code/dns_mapping_ui-master/src/assets/images/background.jpeg b/UI source code/dns_mapping_ui-master/src/assets/images/background.jpeg Binary files differnew file mode 100644 index 0000000..bae295e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/images/background.jpeg diff --git a/UI source code/dns_mapping_ui-master/src/assets/images/logo.png b/UI source code/dns_mapping_ui-master/src/assets/images/logo.png Binary files differnew file mode 100644 index 0000000..f757710 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/images/logo.png diff --git a/UI source code/dns_mapping_ui-master/src/assets/images/newlogo.png b/UI source code/dns_mapping_ui-master/src/assets/images/newlogo.png Binary files differnew file mode 100644 index 0000000..97ef198 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/images/newlogo.png diff --git a/UI source code/dns_mapping_ui-master/src/assets/styles/btn.scss b/UI source code/dns_mapping_ui-master/src/assets/styles/btn.scss new file mode 100644 index 0000000..8f47f2c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/styles/btn.scss @@ -0,0 +1,99 @@ +@import 'variables'; + +@mixin colorBtn($color) { + background: $color; + + &:hover { + color: $color; + + &:before, + &:after { + background: $color; + } + } +} + +.blue-btn { + @include colorBtn($blue) +} + +.light-blue-btn { + @include colorBtn($light-blue) +} + +.red-btn { + @include colorBtn($red) +} + +.pink-btn { + @include colorBtn($pink) +} + +.green-btn { + @include colorBtn($green) +} + +.tiffany-btn { + @include colorBtn($tiffany) +} + +.yellow-btn { + @include colorBtn($yellow) +} + +.pan-btn { + font-size: 14px; + color: #fff; + padding: 14px 36px; + border-radius: 8px; + border: none; + outline: none; + transition: 600ms ease all; + position: relative; + display: inline-block; + + &:hover { + background: #fff; + + &:before, + &:after { + width: 100%; + transition: 600ms ease all; + } + } + + &:before, + &:after { + content: ''; + position: absolute; + top: 0; + right: 0; + height: 2px; + width: 0; + transition: 400ms ease all; + } + + &::after { + right: inherit; + top: inherit; + left: 0; + bottom: 0; + } +} + +.custom-button { + display: inline-block; + line-height: 1; + white-space: nowrap; + cursor: pointer; + background: #fff; + color: #fff; + -webkit-appearance: none; + text-align: center; + box-sizing: border-box; + outline: 0; + margin: 0; + padding: 10px 15px; + font-size: 14px; + border-radius: 4px; +} diff --git a/UI source code/dns_mapping_ui-master/src/assets/styles/eladmin.scss b/UI source code/dns_mapping_ui-master/src/assets/styles/eladmin.scss new file mode 100644 index 0000000..e1e0195 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/styles/eladmin.scss @@ -0,0 +1,117 @@ +.head-container { + padding-bottom: 10px; + .filter-item { + display: inline-block; + vertical-align: middle; + margin: 0 3px 10px 0; + input { + height: 30.5px; + line-height: 30.5px; + } + } + .el-form-item-label { + margin: 0 3px 9px 0; + display: inline-block; + text-align: right; + vertical-align: middle; + font-size: 14px; + color: #606266; + line-height: 30.5px; + padding: 0 7px 0 7px; + } + .el-button+.el-button { + margin-left: 0 !important; + } + .el-select__caret.el-input__icon.el-icon-arrow-up{ + line-height: 30.5px; + } + .date-item { + display: inline-block; + vertical-align: middle; + margin-bottom: 10px; + height: 30.5px !important; + width: 230px !important; + } +} +.el-avatar { + display: inline-block; + text-align: center; + background: #ccc; + color: #fff; + white-space: nowrap; + position: relative; + overflow: hidden; + vertical-align: middle; + width: 32px; + height: 32px; + line-height: 32px; + border-radius: 16px; +} + +.logo-con{ + height: 60px; + padding: 13px 0 0; + img{ + height: 32px; + width: 135px; + display: block; + //margin: 0 auto; + } +} + +#el-login-footer { + height: 40px; + line-height: 40px; + position: fixed; + bottom: 0; + width: 100%; + text-align: center; + color: #fff; + font-family: Arial, serif; + font-size: 12px; + letter-spacing: 1px; +} + +#el-main-footer { + background: none repeat scroll 0 0 white; + border-top: 1px solid #e7eaec; + overflow: hidden; + padding: 10px 6px 0 6px; + height: 33px; + font-size: 0.7rem !important; + color: #7a8b9a; + letter-spacing: 0.8px; + font-family: Arial, sans-serif !important; + position: fixed; + bottom: 0; + z-index: 99; + width: 100%; +} +.eladmin-upload { + border: 1px dashed #c0ccda; + border-radius: 5px; + height: 45px; + line-height: 45px; + width: 368px; +} +.my-blockquote{ + margin: 0 0 10px; + padding: 15px; + line-height: 22px; + border-left: 5px solid #00437B; + border-radius: 0 2px 2px 0; + background-color: #f2f2f2; +} +.my-code{ + position: relative; + padding: 15px; + line-height: 20px; + border-left: 5px solid #ddd; + color: #333; + font-family: Courier New, serif; + font-size: 12px +} + +.el-tabs{ + margin-bottom: 25px; +} diff --git a/UI source code/dns_mapping_ui-master/src/assets/styles/element-ui.scss b/UI source code/dns_mapping_ui-master/src/assets/styles/element-ui.scss new file mode 100644 index 0000000..8f7881c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/styles/element-ui.scss @@ -0,0 +1,79 @@ +// cover some element-ui styles + +.el-breadcrumb__inner, +.el-breadcrumb__inner a { + font-weight: 400 !important; +} + +.el-upload { + input[type="file"] { + display: none !important; + } +} + +.el-upload__input { + display: none; +} + +.cell { + .el-tag { + margin-right: 0; + } +} + +.small-padding { + .cell { + padding-left: 5px; + padding-right: 5px; + } +} + +.fixed-width { + .el-button--mini { + padding: 7px 10px; + width: 60px; + } +} + +.status-col { + .cell { + padding: 0 10px; + text-align: center; + + .el-tag { + margin-right: 0; + } + } +} + +// to fixed https://github.com/ElemeFE/element/issues/2461 +.el-dialog { + transform: none; + left: 0; + position: relative; + margin: 0 auto; +} + +// refine element ui upload +.upload-container { + .el-upload { + width: 100%; + + .el-upload-dragger { + width: 100%; + height: 200px; + } + } +} + +// dropdown +.el-dropdown-menu { + a { + display: block + } +} + +// fix date-picker ui bug in filter-item +.el-range-editor.el-input__inner { + display: inline-flex !important; +} diff --git a/UI source code/dns_mapping_ui-master/src/assets/styles/element-variables.scss b/UI source code/dns_mapping_ui-master/src/assets/styles/element-variables.scss new file mode 100644 index 0000000..a4f8c4a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/styles/element-variables.scss @@ -0,0 +1,31 @@ +/** +* I think element-ui's default theme color is too light for long-term use. +* So I modified the default color and you can modify it to your liking. +**/ + +/* theme color */ +$--color-primary: #1890ff; +$--color-success: #13ce66; +$--color-warning: #FFBA00; +$--color-danger: #ff4949; +// $--color-info: #1E1E1E; + +$--button-font-weight: 400; + +// $--color-text-regular: #1f2d3d; + +$--border-color-light: #dfe4ed; +$--border-color-lighter: #e6ebf5; + +$--table-border:1px solid#dfe6ec; + +/* icon font path, required */ +$--font-path: '~element-ui/lib/theme-chalk/fonts'; + +@import "../../../node_modules/element-ui/packages/theme-chalk/src/index"; + +// the :export directive is the magic sauce for webpack +// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass +:export { + theme: $--color-primary; +} diff --git a/UI source code/dns_mapping_ui-master/src/assets/styles/index.scss b/UI source code/dns_mapping_ui-master/src/assets/styles/index.scss new file mode 100644 index 0000000..7add05b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/styles/index.scss @@ -0,0 +1,182 @@ +@import 'variables'; +@import 'mixin'; +@import 'transition'; +@import 'element-ui'; +@import 'sidebar'; +@import 'btn'; +@import 'eladmin'; + +body { + height: 100%; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; +} + +label { + font-weight: 700; +} + +html { + height: 100%; + box-sizing: border-box; +} + +#app { + height: 100%; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +.no-padding { + padding: 0 !important; +} + +.padding-content { + padding: 4px 0; +} + +a:focus, +a:active { + outline: none; +} + +a, +a:focus, +a:hover { + cursor: pointer; + color: inherit; + text-decoration: none; +} + +div:focus { + outline: none; +} + +.fr { + float: right; +} + +.fl { + float: left; +} + +.pr-5 { + padding-right: 5px; +} + +.pl-5 { + padding-left: 5px; +} + +.block { + display: block; +} + +.pointer { + cursor: pointer; +} + +.inlineBlock { + display: block; +} + +.clearfix { + &:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; + } +} + +aside { + background: #eef1f6; + padding: 8px 24px; + margin-bottom: 20px; + border-radius: 2px; + display: block; + line-height: 32px; + font-size: 16px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + color: #2c3e50; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + a { + color: #337ab7; + cursor: pointer; + + &:hover { + color: rgb(32, 160, 255); + } + } +} + +//main-container全局样式 +.app-container { + padding: 20px 20px 45px 20px; +} + +.components-container { + margin: 30px 50px; + position: relative; +} + +.pagination-container { + margin-top: 30px; +} + +.text-center { + text-align: center +} + +// .sub-navbar { +// height: 50px; +// line-height: 50px; +// position: relative; +// width: 100%; +// text-align: right; +// padding-right: 20px; +// transition: 600ms ease position; +// background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%); + +// .subtitle { +// font-size: 20px; +// color: #fff; +// } + +// &.draft { +// background: #d0d0d0; +// } + +// &.deleted { +// background: #d0d0d0; +// } +// } + +.link-type, +.link-type:focus { + color: #337ab7; + cursor: pointer; + + &:hover { + color: rgb(32, 160, 255); + } +} + +//refine vue-multiselect plugin +.multiselect { + line-height: 16px; +} + +.multiselect--active { + z-index: 1000 !important; +} diff --git a/UI source code/dns_mapping_ui-master/src/assets/styles/mixin.scss b/UI source code/dns_mapping_ui-master/src/assets/styles/mixin.scss new file mode 100644 index 0000000..06fa061 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/styles/mixin.scss @@ -0,0 +1,66 @@ +@mixin clearfix { + &:after { + content: ""; + display: table; + clear: both; + } +} + +@mixin scrollBar { + &::-webkit-scrollbar-track-piece { + background: #d3dce6; + } + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background: #99a9bf; + border-radius: 20px; + } +} + +@mixin relative { + position: relative; + width: 100%; + height: 100%; +} + +@mixin pct($pct) { + width: #{$pct}; + position: relative; + margin: 0 auto; +} + +@mixin triangle($width, $height, $color, $direction) { + $width: $width/2; + $color-border-style: $height solid $color; + $transparent-border-style: $width solid transparent; + height: 0; + width: 0; + + @if $direction==up { + border-bottom: $color-border-style; + border-left: $transparent-border-style; + border-right: $transparent-border-style; + } + + @else if $direction==right { + border-left: $color-border-style; + border-top: $transparent-border-style; + border-bottom: $transparent-border-style; + } + + @else if $direction==down { + border-top: $color-border-style; + border-left: $transparent-border-style; + border-right: $transparent-border-style; + } + + @else if $direction==left { + border-right: $color-border-style; + border-top: $transparent-border-style; + border-bottom: $transparent-border-style; + } +} diff --git a/UI source code/dns_mapping_ui-master/src/assets/styles/sidebar.scss b/UI source code/dns_mapping_ui-master/src/assets/styles/sidebar.scss new file mode 100644 index 0000000..d99315e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/styles/sidebar.scss @@ -0,0 +1,197 @@ +// #app { +// height: 100vh; +// .main-container { +// min-height: 100%; +// transition: margin-left .28s; +// margin-left: $sideBarWidth; +// position: relative; +// } + +// .sidebar-container { +// transition: width 0.28s; +// width: $sideBarWidth !important; +// background-color: $menuBg; +// height: 100%; +// position: fixed; +// font-size: 0; +// top: 0; +// bottom: 0; +// left: 0; +// z-index: 1001; +// overflow: hidden; + +// // reset element-ui css +// .horizontal-collapse-transition { +// transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; +// } + +// .scrollbar-wrapper { +// overflow-x: hidden !important; +// // width: 80% !important; +// // margin-left: -20px; +// } + +// .el-scrollbar__bar.is-vertical { +// right: 0; +// } + +// .el-scrollbar { +// height: 100%; +// width: 80%; +// } + +// &.has-logo { +// .el-scrollbar { +// height: calc(100% - 50px); +// } +// } + +// .is-horizontal { +// display: none; +// } + +// a { +// display: inline-block; +// width: 100%; +// overflow: hidden; +// } + +// .svg-icon { +// margin-right: 16px; +// } + +// .el-menu { +// border: none; +// height: 100%; +// width: 100% !important; +// } + +// // menu hover +// .submenu-title-noDropdown, +// .el-submenu__title { +// &:hover { +// background-color: $menuHover !important; +// } +// } + +// .is-active>.el-submenu__title { +// color: $subMenuActiveText !important; +// font-size: 30px !important; +// } + +// & .nest-menu .el-submenu>.el-submenu__title, +// & .el-submenu .el-menu-item { +// min-width: $sideBarWidth !important; +// background-color: $subMenuBg !important; +// font-size: 30px !important; +// &:hover { +// background-color: $subMenuHover !important; +// } +// } +// } + +// .hideSidebar { +// .sidebar-container { +// width:0px !important; +// } + +// .main-container { +// margin-left:0; +// } + +// .submenu-title-noDropdown { +// padding: 0 !important; +// position: relative; + +// .el-tooltip { +// padding: 0 !important; + +// .svg-icon { +// margin-left: 20px; +// } +// } +// } +// .el-menu--collapse { +// .el-submenu { +// &>.el-submenu__title { +// &>span { +// font-size: 30px !important; +// height: 0; +// width: 0; +// overflow: hidden; +// visibility: hidden; +// display: inline-block; +// } +// } +// } +// } +// } + +// .el-menu--collapse .el-menu .el-submenu { +// min-width: $sideBarWidth !important; +// } + +// // mobile responsive +// .mobile { +// .main-container { +// margin-left: 0; +// } + +// .sidebar-container { +// transition: transform .28s; +// width: $sideBarWidth !important; +// } + +// &.hideSidebar { +// .sidebar-container { +// pointer-events: none; +// transition-duration: 0.3s; +// transform: translate3d(-$sideBarWidth, 0, 0); +// } +// } +// } + +// .withoutAnimation { + +// .main-container, +// .sidebar-container { +// transition: none; +// } +// } +// } + +// // when menu collapsed +// .el-menu--vertical { +// &>.el-menu { +// .svg-icon { +// margin-right: 16px; +// } +// } + +// .nest-menu .el-submenu>.el-submenu__title, +// .el-menu-item { +// &:hover { +// // you can use $subMenuHover +// background-color: $menuHover !important; +// } +// } + +// // the scroll bar appears when the subMenu is too long +// >.el-menu--popup { +// max-height: 100vh; +// overflow-y: auto; + +// &::-webkit-scrollbar-track-piece { +// background: #d3dce6; +// } + +// &::-webkit-scrollbar { +// width: 6px; +// } + +// &::-webkit-scrollbar-thumb { +// background: #99a9bf; +// border-radius: 20px; +// } +// } +// } diff --git a/UI source code/dns_mapping_ui-master/src/assets/styles/transition.scss b/UI source code/dns_mapping_ui-master/src/assets/styles/transition.scss new file mode 100644 index 0000000..4cb27cc --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/styles/transition.scss @@ -0,0 +1,48 @@ +// global transition css + +/* fade */ +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.28s; +} + +.fade-enter, +.fade-leave-active { + opacity: 0; +} + +/* fade-transform */ +.fade-transform-leave-active, +.fade-transform-enter-active { + transition: all .5s; +} + +.fade-transform-enter { + opacity: 0; + transform: translateX(-30px); +} + +.fade-transform-leave-to { + opacity: 0; + transform: translateX(30px); +} + +/* breadcrumb transition */ +.breadcrumb-enter-active, +.breadcrumb-leave-active { + transition: all .5s; +} + +.breadcrumb-enter, +.breadcrumb-leave-active { + opacity: 0; + transform: translateX(20px); +} + +.breadcrumb-move { + transition: all .5s; +} + +.breadcrumb-leave-active { + position: absolute; +} diff --git a/UI source code/dns_mapping_ui-master/src/assets/styles/variables.scss b/UI source code/dns_mapping_ui-master/src/assets/styles/variables.scss new file mode 100644 index 0000000..ba0cd3f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/assets/styles/variables.scss @@ -0,0 +1,35 @@ +// base color +$blue:#324157; +$light-blue:#3A71A8; +$red:#C03639; +$pink: #E65D6E; +$green: #30B08F; +$tiffany: #4AB7BD; +$yellow:#FEC171; +$panGreen: #30B08F; + +// sidebar +$menuText:#bfcbd9; +$menuActiveText:#fff; +$subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951 + +$menuBg:#4608ad; +$menuHover:#263445; + +$subMenuBg:#1f2d3d; +$subMenuHover:#001528; + +$sideBarWidth: 0px; + +// the :export directive is the magic sauce for webpack +// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass +:export { + menuText: $menuText; + menuActiveText: $menuActiveText; + subMenuActiveText: $subMenuActiveText; + menuBg: $menuBg; + menuHover: $menuHover; + subMenuBg: $subMenuBg; + subMenuHover: $subMenuHover; + sideBarWidth: $sideBarWidth; +} diff --git a/UI source code/dns_mapping_ui-master/src/components/Breadcrumb/index.vue b/UI source code/dns_mapping_ui-master/src/components/Breadcrumb/index.vue new file mode 100644 index 0000000..204ea59 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Breadcrumb/index.vue @@ -0,0 +1,81 @@ +<template> + <el-breadcrumb class="app-breadcrumb" separator="/"> + <transition-group name="breadcrumb"> + <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path"> + <span v-if="item.redirect==='noredirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span> + <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a> + </el-breadcrumb-item> + </transition-group> + </el-breadcrumb> +</template> + +<script> +import pathToRegexp from 'path-to-regexp' + +export default { + data() { + return { + levelList: null + } + }, + watch: { + $route(route) { + // if you go to the redirect page, do not update the breadcrumbs + if (route.path.startsWith('/redirect/')) { + return + } + this.getBreadcrumb() + } + }, + created() { + this.getBreadcrumb() + }, + methods: { + getBreadcrumb() { + // only show routes with meta.title + let matched = this.$route.matched.filter(item => item.meta && item.meta.title) + const first = matched[0] + + if (!this.isDashboard(first)) { + matched = [{ path: '/dashboard', meta: { title: '首页' }}].concat(matched) + } + + this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false) + }, + isDashboard(route) { + const name = route && route.name + if (!name) { + return false + } + return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase() + }, + pathCompile(path) { + // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561 + const { params } = this.$route + var toPath = pathToRegexp.compile(path) + return toPath(params) + }, + handleLink(item) { + const { redirect, path } = item + if (redirect) { + this.$router.push(redirect) + return + } + this.$router.push(this.pathCompile(path)) + } + } +} +</script> + +<style lang="scss" scoped> +.app-breadcrumb.el-breadcrumb { + display: inline-block; + font-size: 14px; + line-height: 50px; + margin-left: 8px; + .no-redirect { + color: #97a8be; + cursor: text; + } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Crud/CRUD.operation.vue b/UI source code/dns_mapping_ui-master/src/components/Crud/CRUD.operation.vue new file mode 100644 index 0000000..33d2077 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Crud/CRUD.operation.vue @@ -0,0 +1,268 @@ +<template> + <div class="crud-opts"> + <span class="crud-opts-left"> + <!--左侧插槽--> + <slot name="left" /> + <el-button + v-if="crud.optShow.add" + v-permission="permission.add" + class="filter-item" + size="mini" + type="primary" + icon="el-icon-plus" + @click="crud.toAdd" + > + 新增 + </el-button> + <el-button + v-if="crud.optShow.edit" + v-permission="permission.edit" + class="filter-item" + size="mini" + type="success" + icon="el-icon-edit" + :disabled="crud.selections.length !== 1" + @click="crud.toEdit(crud.selections[0])" + > + 修改 + </el-button> + <el-button + v-if="crud.optShow.del" + slot="reference" + v-permission="permission.del" + class="filter-item" + type="danger" + icon="el-icon-delete" + size="mini" + :loading="crud.delAllLoading" + :disabled="crud.selections.length === 0" + @click="toDelete(crud.selections)" + > + 删除 + </el-button> + <el-button + v-if="crud.optShow.download" + :loading="crud.downloadLoading" + :disabled="!crud.data.length" + class="filter-item" + size="mini" + type="warning" + icon="el-icon-download" + @click="crud.doExport" + >导出</el-button> + <!--右侧--> + <slot name="right" /> + </span> + <el-button-group class="crud-opts-right"> + <el-button + size="mini" + plain + type="info" + icon="el-icon-search" + @click="toggleSearch()" + /> + <el-button + size="mini" + icon="el-icon-refresh" + @click="crud.refresh()" + /> + <el-popover + placement="bottom-end" + width="150" + trigger="click" + > + <el-button + slot="reference" + size="mini" + icon="el-icon-s-grid" + > + <i + class="fa fa-caret-down" + aria-hidden="true" + /> + </el-button> + <el-checkbox + v-model="allColumnsSelected" + :indeterminate="allColumnsSelectedIndeterminate" + @change="handleCheckAllChange" + > + 全选 + </el-checkbox> + <el-checkbox + v-for="item in tableColumns" + :key="item.property" + v-model="item.visible" + @change="handleCheckedTableColumnsChange(item)" + > + {{ item.label }} + </el-checkbox> + </el-popover> + </el-button-group> + </div> +</template> +<script> +import CRUD, { crud } from '@crud/crud' + +function sortWithRef(src, ref) { + const result = Object.assign([], ref) + let cursor = -1 + src.forEach(e => { + const idx = result.indexOf(e) + if (idx === -1) { + cursor += 1 + result.splice(cursor, 0, e) + } else { + cursor = idx + } + }) + return result +} + +export default { + mixins: [crud()], + props: { + permission: { + type: Object, + default: () => { return {} } + }, + hiddenColumns: { + type: Array, + default: () => { return [] } + }, + ignoreColumns: { + type: Array, + default: () => { return [] } + } + }, + data() { + return { + tableColumns: [], + allColumnsSelected: true, + allColumnsSelectedIndeterminate: false, + tableUnwatcher: null, + // 忽略下次表格列变动 + ignoreNextTableColumnsChange: false + } + }, + watch: { + 'crud.props.table'() { + this.updateTableColumns() + this.tableColumns.forEach(column => { + if (this.hiddenColumns.indexOf(column.property) !== -1) { + column.visible = false + this.updateColumnVisible(column) + } + }) + }, + 'crud.props.table.store.states.columns'() { + this.updateTableColumns() + } + }, + created() { + this.crud.updateProp('searchToggle', true) + }, + methods: { + updateTableColumns() { + const table = this.crud.getTable() + if (!table) { + this.tableColumns = [] + return + } + let cols = null + const columnFilter = e => e && e.type === 'default' && e.property && this.ignoreColumns.indexOf(e.property) === -1 + const refCols = table.columns.filter(columnFilter) + if (this.ignoreNextTableColumnsChange) { + this.ignoreNextTableColumnsChange = false + return + } + this.ignoreNextTableColumnsChange = false + const columns = [] + const fullTableColumns = table.$children.map(e => e.columnConfig).filter(columnFilter) + cols = sortWithRef(fullTableColumns, refCols) + cols.forEach(config => { + const column = { + property: config.property, + label: config.label, + visible: refCols.indexOf(config) !== -1 + } + columns.push(column) + }) + this.tableColumns = columns + }, + toDelete(datas) { + this.$confirm(`确认删除选中的${datas.length}条数据?`, '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + this.crud.delAllLoading = true + this.crud.doDelete(datas) + }).catch(() => { + }) + }, + handleCheckAllChange(val) { + if (val === false) { + this.allColumnsSelected = true + return + } + this.tableColumns.forEach(column => { + if (!column.visible) { + column.visible = true + this.updateColumnVisible(column) + } + }) + this.allColumnsSelected = val + this.allColumnsSelectedIndeterminate = false + }, + handleCheckedTableColumnsChange(item) { + let totalCount = 0 + let selectedCount = 0 + this.tableColumns.forEach(column => { + ++totalCount + selectedCount += column.visible ? 1 : 0 + }) + if (selectedCount === 0) { + this.crud.notify('请至少选择一列', CRUD.NOTIFICATION_TYPE.WARNING) + this.$nextTick(function() { + item.visible = true + }) + return + } + this.allColumnsSelected = selectedCount === totalCount + this.allColumnsSelectedIndeterminate = selectedCount !== totalCount && selectedCount !== 0 + this.updateColumnVisible(item) + }, + updateColumnVisible(item) { + const table = this.crud.props.table + const vm = table.$children.find(e => e.prop === item.property) + const columnConfig = vm.columnConfig + if (item.visible) { + // 找出合适的插入点 + const columnIndex = this.tableColumns.indexOf(item) + vm.owner.store.commit('insertColumn', columnConfig, columnIndex + 1, null) + } else { + vm.owner.store.commit('removeColumn', columnConfig, null) + } + this.ignoreNextTableColumnsChange = true + }, + toggleSearch() { + this.crud.props.searchToggle = !this.crud.props.searchToggle + } + } +} +</script> + +<style> + .crud-opts { + padding: 4px 0; + display: -webkit-flex; + display: flex; + align-items: center; + } + .crud-opts .crud-opts-right { + margin-left: auto; + } + .crud-opts .crud-opts-right span { + float: left; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Crud/Pagination.vue b/UI source code/dns_mapping_ui-master/src/components/Crud/Pagination.vue new file mode 100644 index 0000000..d4482fb --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Crud/Pagination.vue @@ -0,0 +1,18 @@ +<!--分页--> +<template> + <el-pagination + :page-size.sync="page.size" + :total="page.total" + :current-page.sync="page.page" + style="margin-top: 8px;" + layout="total, prev, pager, next, sizes" + @size-change="crud.sizeChangeHandler($event)" + @current-change="crud.pageChangeHandler" + /> +</template> +<script> +import { pagination } from '@crud/crud' +export default { + mixins: [pagination()] +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/Crud/RR.operation.vue b/UI source code/dns_mapping_ui-master/src/components/Crud/RR.operation.vue new file mode 100644 index 0000000..df2c138 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Crud/RR.operation.vue @@ -0,0 +1,20 @@ +<!--搜索与重置--> +<template> + <span> + <el-button class="filter-item" size="mini" type="success" icon="el-icon-search" @click="crud.toQuery">搜索</el-button> + <el-button v-if="crud.optShow.reset" class="filter-item" size="mini" type="warning" icon="el-icon-refresh-left" @click="crud.resetQuery()">重置</el-button> + </span> +</template> +<script> +import { crud } from '@crud/crud' +export default { + mixins: [crud()], + props: { + itemClass: { + type: String, + required: false, + default: '' + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/Crud/UD.operation.vue b/UI source code/dns_mapping_ui-master/src/components/Crud/UD.operation.vue new file mode 100644 index 0000000..c60abd7 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Crud/UD.operation.vue @@ -0,0 +1,71 @@ +<template> + <div> + <el-button v-permission="permission.edit" :loading="crud.status.cu === 2" :disabled="disabledEdit" size="mini" type="primary" icon="el-icon-edit" @click="crud.toEdit(data)" /> + <el-popover v-model="pop" v-permission="permission.del" placement="top" width="180" trigger="manual" @show="onPopoverShow" @hide="onPopoverHide"> + <p>{{ msg }}</p> + <div style="text-align: right; margin: 0"> + <el-button size="mini" type="text" @click="doCancel">取消</el-button> + <el-button :loading="crud.dataStatus[crud.getDataId(data)].delete === 2" type="primary" size="mini" @click="crud.doDelete(data)">确定</el-button> + </div> + <el-button slot="reference" :disabled="disabledDle" type="danger" icon="el-icon-delete" size="mini" @click="toDelete" /> + </el-popover> + </div> +</template> +<script> +import CRUD, { crud } from '@crud/crud' +export default { + mixins: [crud()], + props: { + data: { + type: Object, + required: true + }, + permission: { + type: Object, + required: true + }, + disabledEdit: { + type: Boolean, + default: false + }, + disabledDle: { + type: Boolean, + default: false + }, + msg: { + type: String, + default: '确定删除本条数据吗?' + } + }, + data() { + return { + pop: false + } + }, + methods: { + doCancel() { + this.pop = false + this.crud.cancelDelete(this.data) + }, + toDelete() { + this.pop = true + }, + [CRUD.HOOK.afterDelete](crud, data) { + if (data === this.data) { + this.pop = false + } + }, + onPopoverShow() { + setTimeout(() => { + document.addEventListener('click', this.handleDocumentClick) + }, 0) + }, + onPopoverHide() { + document.removeEventListener('click', this.handleDocumentClick) + }, + handleDocumentClick(event) { + this.pop = false + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/Crud/crud.js b/UI source code/dns_mapping_ui-master/src/components/Crud/crud.js new file mode 100644 index 0000000..ae36765 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Crud/crud.js @@ -0,0 +1,863 @@ +import { initData, download } from '@/api/data' +import { parseTime, downloadFile } from '@/utils/index' +import Vue from 'vue' + +/** + * CRUD配置 + * @author moxun + * @param {*} options <br> + * @return crud instance. + * @example + * 要使用多crud时,请在关联crud的组件处使用crud-tag进行标记,如:<jobForm :job-status="dict.job_status" crud-tag="job" /> + */ +function CRUD(options) { + const defaultOptions = { + tag: 'default', + // id字段名 + idField: 'id', + // 标题 + title: '', + // 请求数据的url + url: '', + // 表格数据 + data: [], + // 选择项 + selections: [], + // 待查询的对象 + query: {}, + // 查询数据的参数 + params: {}, + // Form 表单 + form: {}, + // 重置表单 + defaultForm: () => {}, + // 排序规则,默认 id 降序, 支持多字段排序 ['id,desc', 'createTime,asc'] + sort: ['id,desc'], + // 等待时间 + time: 50, + // CRUD Method + crudMethod: { + add: (form) => {}, + del: (id) => {}, + edit: (form) => {}, + get: (id) => {} + }, + // 主页操作栏显示哪些按钮 + optShow: { + add: true, + edit: true, + del: true, + download: true, + reset: true + }, + // 自定义一些扩展属性 + props: {}, + // 在主页准备 + queryOnPresenterCreated: true, + // 调试开关 + debug: false + } + options = mergeOptions(defaultOptions, options) + const data = { + ...options, + // 记录数据状态 + dataStatus: {}, + status: { + add: CRUD.STATUS.NORMAL, + edit: CRUD.STATUS.NORMAL, + // 添加或编辑状态 + get cu() { + if (this.add === CRUD.STATUS.NORMAL && this.edit === CRUD.STATUS.NORMAL) { + return CRUD.STATUS.NORMAL + } else if (this.add === CRUD.STATUS.PREPARED || this.edit === CRUD.STATUS.PREPARED) { + return CRUD.STATUS.PREPARED + } else if (this.add === CRUD.STATUS.PROCESSING || this.edit === CRUD.STATUS.PROCESSING) { + return CRUD.STATUS.PROCESSING + } + throw new Error('wrong crud\'s cu status') + }, + // 标题 + get title() { + return this.add > CRUD.STATUS.NORMAL ? `新增${crud.title}` : this.edit > CRUD.STATUS.NORMAL ? `编辑${crud.title}` : crud.title + } + }, + msg: { + submit: '提交成功', + add: '新增成功', + edit: '编辑成功', + del: '删除成功' + }, + page: { + // 页码 + page: 0, + // 每页数据条数 + size: 10, + // 总数据条数 + total: 0 + }, + // 整体loading + loading: false, + // 导出的 Loading + downloadLoading: false, + // 删除的 Loading + delAllLoading: false + } + const methods = { + /** + * 通用的提示 + */ + submitSuccessNotify() { + crud.notify(crud.msg.submit, CRUD.NOTIFICATION_TYPE.SUCCESS) + }, + addSuccessNotify() { + crud.notify(crud.msg.add, CRUD.NOTIFICATION_TYPE.SUCCESS) + }, + editSuccessNotify() { + crud.notify(crud.msg.edit, CRUD.NOTIFICATION_TYPE.SUCCESS) + }, + delSuccessNotify() { + crud.notify(crud.msg.del, CRUD.NOTIFICATION_TYPE.SUCCESS) + }, + // 搜索 + toQuery() { + crud.page.page = 1 + crud.refresh() + }, + // 刷新 + refresh() { + if (!callVmHook(crud, CRUD.HOOK.beforeRefresh)) { + return + } + return new Promise((resolve, reject) => { + crud.loading = true + // 请求数据 + initData(crud.url, crud.getQueryParams()).then(data => { + const table = crud.getTable() + if (table && table.lazy) { // 懒加载子节点数据,清掉已加载的数据 + table.store.states.treeData = {} + table.store.states.lazyTreeNodeMap = {} + } + crud.page.total = data.totalElements + crud.data = data.content + crud.resetDataStatus() + // time 毫秒后显示表格 + setTimeout(() => { + crud.loading = false + callVmHook(crud, CRUD.HOOK.afterRefresh) + }, crud.time) + resolve(data) + }).catch(err => { + crud.loading = false + reject(err) + }) + }) + }, + /** + * 启动添加 + */ + toAdd() { + crud.resetForm() + if (!(callVmHook(crud, CRUD.HOOK.beforeToAdd, crud.form) && callVmHook(crud, CRUD.HOOK.beforeToCU, crud.form))) { + return + } + crud.status.add = CRUD.STATUS.PREPARED + callVmHook(crud, CRUD.HOOK.afterToAdd, crud.form) + callVmHook(crud, CRUD.HOOK.afterToCU, crud.form) + }, + /** + * 启动编辑 + * @param {*} data 数据项 + */ + toEdit(data) { + crud.resetForm(JSON.parse(JSON.stringify(data))) + if (!(callVmHook(crud, CRUD.HOOK.beforeToEdit, crud.form) && callVmHook(crud, CRUD.HOOK.beforeToCU, crud.form))) { + return + } + crud.status.edit = CRUD.STATUS.PREPARED + crud.getDataStatus(crud.getDataId(data)).edit = CRUD.STATUS.PREPARED + callVmHook(crud, CRUD.HOOK.afterToEdit, crud.form) + callVmHook(crud, CRUD.HOOK.afterToCU, crud.form) + }, + /** + * 启动删除 + * @param {*} data 数据项 + */ + toDelete(data) { + crud.getDataStatus(crud.getDataId(data)).delete = CRUD.STATUS.PREPARED + }, + /** + * 取消删除 + * @param {*} data 数据项 + */ + cancelDelete(data) { + if (!callVmHook(crud, CRUD.HOOK.beforeDeleteCancel, data)) { + return + } + crud.getDataStatus(crud.getDataId(data)).delete = CRUD.STATUS.NORMAL + callVmHook(crud, CRUD.HOOK.afterDeleteCancel, data) + }, + /** + * 取消新增/编辑 + */ + cancelCU() { + const addStatus = crud.status.add + const editStatus = crud.status.edit + if (addStatus === CRUD.STATUS.PREPARED) { + if (!callVmHook(crud, CRUD.HOOK.beforeAddCancel, crud.form)) { + return + } + crud.status.add = CRUD.STATUS.NORMAL + } + if (editStatus === CRUD.STATUS.PREPARED) { + if (!callVmHook(crud, CRUD.HOOK.beforeEditCancel, crud.form)) { + return + } + crud.status.edit = CRUD.STATUS.NORMAL + crud.getDataStatus(crud.getDataId(crud.form)).edit = CRUD.STATUS.NORMAL + } + crud.resetForm() + if (addStatus === CRUD.STATUS.PREPARED) { + callVmHook(crud, CRUD.HOOK.afterAddCancel, crud.form) + } + if (editStatus === CRUD.STATUS.PREPARED) { + callVmHook(crud, CRUD.HOOK.afterEditCancel, crud.form) + } + // 清除表单验证 + if (crud.findVM('form').$refs['form']) { + crud.findVM('form').$refs['form'].clearValidate() + } + }, + /** + * 提交新增/编辑 + */ + submitCU() { + if (!callVmHook(crud, CRUD.HOOK.beforeValidateCU)) { + return + } + crud.findVM('form').$refs['form'].validate(valid => { + if (!valid) { + return + } + if (!callVmHook(crud, CRUD.HOOK.afterValidateCU)) { + return + } + if (crud.status.add === CRUD.STATUS.PREPARED) { + crud.doAdd() + } else if (crud.status.edit === CRUD.STATUS.PREPARED) { + crud.doEdit() + } + }) + }, + /** + * 执行添加 + */ + doAdd() { + if (!callVmHook(crud, CRUD.HOOK.beforeSubmit)) { + return + } + crud.status.add = CRUD.STATUS.PROCESSING + crud.crudMethod.add(crud.form).then(() => { + crud.status.add = CRUD.STATUS.NORMAL + crud.resetForm() + crud.addSuccessNotify() + callVmHook(crud, CRUD.HOOK.afterSubmit) + crud.toQuery() + }).catch(() => { + crud.status.add = CRUD.STATUS.PREPARED + callVmHook(crud, CRUD.HOOK.afterAddError) + }) + }, + /** + * 执行编辑 + */ + doEdit() { + if (!callVmHook(crud, CRUD.HOOK.beforeSubmit)) { + return + } + crud.status.edit = CRUD.STATUS.PROCESSING + crud.crudMethod.edit(crud.form).then(() => { + crud.status.edit = CRUD.STATUS.NORMAL + crud.getDataStatus(crud.getDataId(crud.form)).edit = CRUD.STATUS.NORMAL + crud.editSuccessNotify() + crud.resetForm() + callVmHook(crud, CRUD.HOOK.afterSubmit) + crud.refresh() + }).catch(() => { + crud.status.edit = CRUD.STATUS.PREPARED + callVmHook(crud, CRUD.HOOK.afterEditError) + }) + }, + /** + * 执行删除 + * @param {*} data 数据项 + */ + doDelete(data) { + let delAll = false + let dataStatus + const ids = [] + if (data instanceof Array) { + delAll = true + data.forEach(val => { + ids.push(this.getDataId(val)) + }) + } else { + ids.push(this.getDataId(data)) + dataStatus = crud.getDataStatus(this.getDataId(data)) + } + if (!callVmHook(crud, CRUD.HOOK.beforeDelete, data)) { + return + } + if (!delAll) { + dataStatus.delete = CRUD.STATUS.PROCESSING + } + return crud.crudMethod.del(ids).then(() => { + if (delAll) { + crud.delAllLoading = false + } else dataStatus.delete = CRUD.STATUS.PREPARED + crud.dleChangePage(1) + crud.delSuccessNotify() + callVmHook(crud, CRUD.HOOK.afterDelete, data) + crud.refresh() + }).catch(() => { + if (delAll) { + crud.delAllLoading = false + } else dataStatus.delete = CRUD.STATUS.PREPARED + }) + }, + /** + * 通用导出 + */ + doExport() { + crud.downloadLoading = true + download(crud.url + '/download', crud.getQueryParams()).then(result => { + downloadFile(result, crud.title + '数据', 'xlsx') + crud.downloadLoading = false + }).catch(() => { + crud.downloadLoading = false + }) + }, + /** + * 获取查询参数 + */ + getQueryParams: function() { + // 清除参数无值的情况 + Object.keys(crud.query).length !== 0 && Object.keys(crud.query).forEach(item => { + if (crud.query[item] === null || crud.query[item] === '') crud.query[item] = undefined + }) + Object.keys(crud.params).length !== 0 && Object.keys(crud.params).forEach(item => { + if (crud.params[item] === null || crud.params[item] === '') crud.params[item] = undefined + }) + return { + page: crud.page.page - 1, + size: crud.page.size, + sort: crud.sort, + ...crud.query, + ...crud.params + } + }, + // 当前页改变 + pageChangeHandler(e) { + crud.page.page = e + crud.refresh() + }, + // 每页条数改变 + sizeChangeHandler(e) { + crud.page.size = e + crud.page.page = 1 + crud.refresh() + }, + // 预防删除第二页最后一条数据时,或者多选删除第二页的数据时,页码错误导致请求无数据 + dleChangePage(size) { + if (crud.data.length === size && crud.page.page !== 1) { + crud.page.page -= 1 + } + }, + // 选择改变 + selectionChangeHandler(val) { + crud.selections = val + }, + /** + * 重置查询参数 + * @param {Boolean} toQuery 重置后进行查询操作 + */ + resetQuery(toQuery = true) { + const defaultQuery = JSON.parse(JSON.stringify(crud.defaultQuery)) + const query = crud.query + Object.keys(query).forEach(key => { + query[key] = defaultQuery[key] + }) + // 重置参数 + this.params = {} + if (toQuery) { + crud.toQuery() + } + }, + /** + * 重置表单 + * @param {Array} data 数据 + */ + resetForm(data) { + const form = data || (typeof crud.defaultForm === 'object' ? JSON.parse(JSON.stringify(crud.defaultForm)) : crud.defaultForm.apply(crud.findVM('form'))) + const crudFrom = crud.form + for (const key in form) { + if (crudFrom.hasOwnProperty(key)) { + crudFrom[key] = form[key] + } else { + Vue.set(crudFrom, key, form[key]) + } + } + // add by ghl 2020-10-04 页面重复添加信息时,下拉框的校验会存在,需要找工取消 + if (crud.findVM('form').$refs['form']) { + crud.findVM('form').$refs['form'].clearValidate() + } + }, + /** + * 重置数据状态 + */ + resetDataStatus() { + const dataStatus = {} + function resetStatus(datas) { + datas.forEach(e => { + dataStatus[crud.getDataId(e)] = { + delete: 0, + edit: 0 + } + if (e.children) { + resetStatus(e.children) + } + }) + } + resetStatus(crud.data) + crud.dataStatus = dataStatus + }, + /** + * 获取数据状态 + * @param {Number | String} id 数据项id + */ + getDataStatus(id) { + return crud.dataStatus[id] + }, + /** + * 用于树形表格多选, 选中所有 + * @param selection + */ + selectAllChange(selection) { + // 如果选中的数目与请求到的数目相同就选中子节点,否则就清空选中 + if (selection && selection.length === crud.data.length) { + selection.forEach(val => { + crud.selectChange(selection, val) + }) + } else { + crud.getTable().clearSelection() + } + }, + /** + * 用于树形表格多选,单选的封装 + * @param selection + * @param row + */ + selectChange(selection, row) { + // 如果selection中存在row代表是选中,否则是取消选中 + if (selection.find(val => { return crud.getDataId(val) === crud.getDataId(row) })) { + if (row.children) { + row.children.forEach(val => { + crud.getTable().toggleRowSelection(val, true) + selection.push(val) + if (val.children) { + crud.selectChange(selection, val) + } + }) + } + } else { + crud.toggleRowSelection(selection, row) + } + }, + /** + * 切换选中状态 + * @param selection + * @param data + */ + toggleRowSelection(selection, data) { + if (data.children) { + data.children.forEach(val => { + crud.getTable().toggleRowSelection(val, false) + if (val.children) { + crud.toggleRowSelection(selection, val) + } + }) + } + }, + findVM(type) { + return crud.vms.find(vm => vm && vm.type === type).vm + }, + notify(title, type = CRUD.NOTIFICATION_TYPE.INFO) { + crud.vms[0].vm.$notify({ + title, + type, + duration: 2500 + }) + }, + updateProp(name, value) { + Vue.set(crud.props, name, value) + }, + getDataId(data) { + return data[this.idField] + }, + getTable() { + return this.findVM('presenter').$refs.table + }, + attchTable() { + const table = this.getTable() + this.updateProp('table', table) + const that = this + table.$on('expand-change', (row, expanded) => { + if (!expanded) { + return + } + const lazyTreeNodeMap = table.store.states.lazyTreeNodeMap + row.children = lazyTreeNodeMap[crud.getDataId(row)] + if (row.children) { + row.children.forEach(ele => { + const id = crud.getDataId(ele) + if (that.dataStatus[id] === undefined) { + that.dataStatus[id] = { + delete: 0, + edit: 0 + } + } + }) + } + }) + } + } + const crud = Object.assign({}, data) + // 可观测化 + Vue.observable(crud) + // 附加方法 + Object.assign(crud, methods) + // 记录初始默认的查询参数,后续重置查询时使用 + Object.assign(crud, { + defaultQuery: JSON.parse(JSON.stringify(data.query)), + // 预留4位存储:组件 主页、头部、分页、表单,调试查看也方便找 + vms: Array(4), + /** + * 注册组件实例 + * @param {String} type 类型 + * @param {*} vm 组件实例 + * @param {Number} index 该参数内部使用 + */ + registerVM(type, vm, index = -1) { + const vmObj = { + type, + vm: vm + } + if (index < 0) { + this.vms.push(vmObj) + return + } + if (index < 4) { // 内置预留vm数 + this.vms[index] = vmObj + return + } + this.vms.length = Math.max(this.vms.length, index) + this.vms.splice(index, 1, vmObj) + }, + /** + * 取消注册组件实例 + * @param {*} vm 组件实例 + */ + unregisterVM(type, vm) { + for (let i = this.vms.length - 1; i >= 0; i--) { + if (this.vms[i] === undefined) { + continue + } + if (this.vms[i].type === type && this.vms[i].vm === vm) { + if (i < 4) { // 内置预留vm数 + this.vms[i] = undefined + } else { + this.vms.splice(i, 1) + } + break + } + } + } + }) + // 冻结处理,需要扩展数据的话,使用crud.updateProp(name, value),以crud.props.name形式访问,这个是响应式的,可以做数据绑定 + Object.freeze(crud) + return crud +} + +// hook VM +function callVmHook(crud, hook) { + if (crud.debug) { + console.log('callVmHook: ' + hook) + } + const tagHook = crud.tag ? hook + '$' + crud.tag : null + let ret = true + const nargs = [crud] + for (let i = 2; i < arguments.length; ++i) { + nargs.push(arguments[i]) + } + // 有些组件扮演了多个角色,调用钩子时,需要去重 + const vmSet = new Set() + crud.vms.forEach(vm => vm && vmSet.add(vm.vm)) + vmSet.forEach(vm => { + if (vm[hook]) { + ret = vm[hook].apply(vm, nargs) !== false && ret + } + if (tagHook && vm[tagHook]) { + ret = vm[tagHook].apply(vm, nargs) !== false && ret + } + }) + return ret +} + +function mergeOptions(src, opts) { + const optsRet = { + ...src + } + for (const key in src) { + if (opts.hasOwnProperty(key)) { + optsRet[key] = opts[key] + } + } + return optsRet +} + +/** + * 查找crud + * @param {*} vm + * @param {string} tag + */ +function lookupCrud(vm, tag) { + tag = tag || vm.$attrs['crud-tag'] || 'default' + // function lookupCrud(vm, tag) { + if (vm.$crud) { + const ret = vm.$crud[tag] + if (ret) { + return ret + } + } + return vm.$parent ? lookupCrud(vm.$parent, tag) : undefined +} + +/** + * crud主页 + */ +function presenter(crud) { + if (crud) { + console.warn('[CRUD warn]: ' + 'please use $options.cruds() { return CRUD(...) or [CRUD(...), ...] }') + } + return { + data() { + // 在data中返回crud,是为了将crud与当前实例关联,组件观测crud相关属性变化 + return { + crud: this.crud + } + }, + beforeCreate() { + this.$crud = this.$crud || {} + let cruds = this.$options.cruds instanceof Function ? this.$options.cruds() : crud + if (!(cruds instanceof Array)) { + cruds = [cruds] + } + cruds.forEach(ele => { + if (this.$crud[ele.tag]) { + console.error('[CRUD error]: ' + 'crud with tag [' + ele.tag + ' is already exist') + } + this.$crud[ele.tag] = ele + ele.registerVM('presenter', this, 0) + }) + this.crud = this.$crud['defalut'] || cruds[0] + }, + methods: { + parseTime + }, + created() { + for (const k in this.$crud) { + if (this.$crud[k].queryOnPresenterCreated) { + this.$crud[k].toQuery() + } + } + }, + destroyed() { + for (const k in this.$crud) { + this.$crud[k].unregisterVM('presenter', this) + } + }, + mounted() { + // 如果table未实例化(例如使用了v-if),请稍后在适当时机crud.attchTable刷新table信息 + if (this.$refs.table !== undefined) { + this.crud.attchTable() + } + } + } +} + +/** + * 头部 + */ +function header() { + return { + data() { + return { + crud: this.crud, + query: this.crud.query + } + }, + beforeCreate() { + this.crud = lookupCrud(this) + this.crud.registerVM('header', this, 1) + }, + destroyed() { + this.crud.unregisterVM('header', this) + } + } +} + +/** + * 分页 + */ +function pagination() { + return { + data() { + return { + crud: this.crud, + page: this.crud.page + } + }, + beforeCreate() { + this.crud = lookupCrud(this) + this.crud.registerVM('pagination', this, 2) + }, + destroyed() { + this.crud.unregisterVM('pagination', this) + } + } +} + +/** + * 表单 + */ +function form(defaultForm) { + return { + data() { + return { + crud: this.crud, + form: this.crud.form + } + }, + beforeCreate() { + this.crud = lookupCrud(this) + this.crud.registerVM('form', this, 3) + }, + created() { + this.crud.defaultForm = defaultForm + this.crud.resetForm() + }, + destroyed() { + this.crud.unregisterVM('form', this) + } + } +} + +/** + * crud + */ +function crud(options = {}) { + const defaultOptions = { + type: undefined + } + options = mergeOptions(defaultOptions, options) + return { + data() { + return { + crud: this.crud + } + }, + beforeCreate() { + this.crud = lookupCrud(this) + this.crud.registerVM(options.type, this) + }, + destroyed() { + this.crud.unregisterVM(options.type, this) + } + } +} + +/** + * CRUD钩子 + */ +CRUD.HOOK = { + /** 刷新 - 之前 */ + beforeRefresh: 'beforeCrudRefresh', + /** 刷新 - 之后 */ + afterRefresh: 'afterCrudRefresh', + /** 删除 - 之前 */ + beforeDelete: 'beforeCrudDelete', + /** 删除 - 之后 */ + afterDelete: 'afterCrudDelete', + /** 删除取消 - 之前 */ + beforeDeleteCancel: 'beforeCrudDeleteCancel', + /** 删除取消 - 之后 */ + afterDeleteCancel: 'afterCrudDeleteCancel', + /** 新建 - 之前 */ + beforeToAdd: 'beforeCrudToAdd', + /** 新建 - 之后 */ + afterToAdd: 'afterCrudToAdd', + /** 编辑 - 之前 */ + beforeToEdit: 'beforeCrudToEdit', + /** 编辑 - 之后 */ + afterToEdit: 'afterCrudToEdit', + /** 开始 "新建/编辑" - 之前 */ + beforeToCU: 'beforeCrudToCU', + /** 开始 "新建/编辑" - 之后 */ + afterToCU: 'afterCrudToCU', + /** "新建/编辑" 验证 - 之前 */ + beforeValidateCU: 'beforeCrudValidateCU', + /** "新建/编辑" 验证 - 之后 */ + afterValidateCU: 'afterCrudValidateCU', + /** 添加取消 - 之前 */ + beforeAddCancel: 'beforeCrudAddCancel', + /** 添加取消 - 之后 */ + afterAddCancel: 'afterCrudAddCancel', + /** 编辑取消 - 之前 */ + beforeEditCancel: 'beforeCrudEditCancel', + /** 编辑取消 - 之后 */ + afterEditCancel: 'afterCrudEditCancel', + /** 提交 - 之前 */ + beforeSubmit: 'beforeCrudSubmitCU', + /** 提交 - 之后 */ + afterSubmit: 'afterCrudSubmitCU', + afterAddError: 'afterCrudAddError', + afterEditError: 'afterCrudEditError' +} + +/** + * CRUD状态 + */ +CRUD.STATUS = { + NORMAL: 0, + PREPARED: 1, + PROCESSING: 2 +} + +/** + * CRUD通知类型 + */ +CRUD.NOTIFICATION_TYPE = { + SUCCESS: 'success', + WARNING: 'warning', + INFO: 'info', + ERROR: 'error' +} + +export default CRUD + +export { + presenter, + header, + form, + pagination, + crud +} diff --git a/UI source code/dns_mapping_ui-master/src/components/DateRangePicker/index.vue b/UI source code/dns_mapping_ui-master/src/components/DateRangePicker/index.vue new file mode 100644 index 0000000..eef79bd --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/DateRangePicker/index.vue @@ -0,0 +1,45 @@ +<script> +import { DatePicker, DatePickerOptions } from 'element-ui' +import { calendarShortcuts } from '@/utils/shortcuts' + +export default { + name: 'DateRangePicker', + mixins: [DatePicker], + props: { + type: { + type: String, + default: 'daterange' + }, + valueFormat: { + type: String, + default: 'yyyy-MM-dd HH:mm:ss' + }, + defaultTime: { + type: Array, + default: _ => ['00:00:00', '23:59:59'] + }, + pickerOptions: { + type: DatePickerOptions, + default: _ => { + return { shortcuts: calendarShortcuts } + } + }, + size: { + type: String, + default: 'small' + }, + rangeSeparator: { + type: String, + default: ':' + }, + startPlaceholder: { + type: String, + default: '开始日期' + }, + endPlaceholder: { + type: String, + default: '结束日期' + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/Dict/Dict.js b/UI source code/dns_mapping_ui-master/src/components/Dict/Dict.js new file mode 100644 index 0000000..48554de --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Dict/Dict.js @@ -0,0 +1,29 @@ +import Vue from 'vue' +import { get as getDictDetail } from '@/api/system/dictDetail' + +export default class Dict { + constructor(dict) { + this.dict = dict + } + + async init(names, completeCallback) { + if (names === undefined || name === null) { + throw new Error('need Dict names') + } + const ps = [] + names.forEach(n => { + Vue.set(this.dict.dict, n, {}) + Vue.set(this.dict.label, n, {}) + Vue.set(this.dict, n, []) + ps.push(getDictDetail(n).then(data => { + this.dict[n].splice(0, 0, ...data.content) + data.content.forEach(d => { + Vue.set(this.dict.dict[n], d.value, d) + Vue.set(this.dict.label[n], d.value, d.label) + }) + })) + }) + await Promise.all(ps) + completeCallback() + } +} diff --git a/UI source code/dns_mapping_ui-master/src/components/Dict/index.js b/UI source code/dns_mapping_ui-master/src/components/Dict/index.js new file mode 100644 index 0000000..0952f43 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Dict/index.js @@ -0,0 +1,29 @@ +import Dict from './Dict' + +const install = function(Vue) { + Vue.mixin({ + data() { + if (this.$options.dicts instanceof Array) { + const dict = { + dict: {}, + label: {} + } + return { + dict + } + } + return {} + }, + created() { + if (this.$options.dicts instanceof Array) { + new Dict(this.dict).init(this.$options.dicts, () => { + this.$nextTick(() => { + this.$emit('dictReady') + }) + }) + } + } + }) +} + +export default { install } diff --git a/UI source code/dns_mapping_ui-master/src/components/Doc/index.vue b/UI source code/dns_mapping_ui-master/src/components/Doc/index.vue new file mode 100644 index 0000000..47c5e8d --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Doc/index.vue @@ -0,0 +1,16 @@ +<template> + <div> + <svg-icon icon-class="doc" @click="click" /> + </div> +</template> + +<script> +export default { + name: 'Doc', + methods: { + click() { + window.open('https://el-admin.vip/pages/010101/', '_blank') + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/BarChart.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/BarChart.vue new file mode 100644 index 0000000..fa265ef --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/BarChart.vue @@ -0,0 +1,106 @@ +<template> + <div :class="className" :style="{height:height,width:width}" /> +</template> + +<script> +import echarts from 'echarts' +require('echarts/theme/macarons') // echarts theme +import { debounce } from '@/utils' + +const animationDuration = 6000 + +export default { + props: { + className: { + type: String, + default: 'chart' + }, + width: { + type: String, + default: '100%' + }, + height: { + type: String, + default: '300px' + } + }, + data() { + return { + chart: null + } + }, + mounted() { + this.initChart() + this.__resizeHandler = debounce(() => { + if (this.chart) { + this.chart.resize() + } + }, 100) + window.addEventListener('resize', this.__resizeHandler) + }, + beforeDestroy() { + if (!this.chart) { + return + } + window.removeEventListener('resize', this.__resizeHandler) + this.chart.dispose() + this.chart = null + }, + methods: { + initChart() { + this.chart = echarts.init(this.$el, 'macarons') + + this.chart.setOption({ + tooltip: { + trigger: 'axis', + axisPointer: { // 坐标轴指示器,坐标轴触发有效 + type: 'shadow' // 默认为直线,可选为:'line' | 'shadow' + } + }, + grid: { + top: 10, + left: '2%', + right: '2%', + bottom: '3%', + containLabel: true + }, + xAxis: [{ + type: 'category', + data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + axisTick: { + alignWithLabel: true + } + }], + yAxis: [{ + type: 'value', + axisTick: { + show: false + } + }], + series: [{ + name: 'pageA', + type: 'bar', + stack: 'vistors', + barWidth: '60%', + data: [79, 52, 200, 334, 390, 330, 220], + animationDuration + }, { + name: 'pageB', + type: 'bar', + stack: 'vistors', + barWidth: '60%', + data: [80, 52, 200, 334, 390, 330, 220], + animationDuration + }, { + name: 'pageC', + type: 'bar', + stack: 'vistors', + barWidth: '60%', + data: [30, 52, 200, 334, 390, 330, 220], + animationDuration + }] + }) + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Category.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Category.vue new file mode 100644 index 0000000..5859114 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Category.vue @@ -0,0 +1,438 @@ +<template> + <div :class="className" :style="{height:height,width:width}" /> +</template> + +<script> +import echarts from 'echarts' + +require('echarts/theme/macarons') // echarts theme +import { debounce } from '@/utils' + +export default { + props: { + className: { + type: String, + default: 'chart' + }, + width: { + type: String, + default: '100%' + }, + height: { + type: String, + default: '500px' + } + }, + data() { + return { + chart: null + } + }, + mounted() { + this.initChart() + this.__resizeHandler = debounce(() => { + if (this.chart) { + this.chart.resize() + } + }, 100) + window.addEventListener('resize', this.__resizeHandler) + }, + beforeDestroy() { + if (!this.chart) { + return + } + window.removeEventListener('resize', this.__resizeHandler) + this.chart.dispose() + this.chart = null + }, + methods: { + initChart() { + this.chart = echarts.init(this.$el, 'macarons') + const dataMap = {} + + function dataFormatter(obj) { + const pList = ['北京', '天津', '河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江', '上海', '江苏', '浙江', '安徽', '福建', '江西', '山东', '河南', '湖北', '湖南', '广东', '广西', '海南', '重庆', '四川', '贵州', '云南', '西藏', '陕西', '甘肃', '青海', '宁夏', '新疆'] + let temp + for (let year = 2002; year <= 2011; year++) { + let max = 0 + let sum = 0 + temp = obj[year] + for (let i = 0, l = temp.length; i < l; i++) { + max = Math.max(max, temp[i]) + sum += temp[i] + obj[year][i] = { + name: pList[i], + value: temp[i] + } + } + obj[year + 'max'] = Math.floor(max / 100) * 100 + obj[year + 'sum'] = sum + } + return obj + } + + dataMap.dataGDP = dataFormatter({ + 2011: [16251.93, 11307.28, 24515.76, 11237.55, 14359.88, 22226.7, 10568.83, 12582, 19195.69, 49110.27, 32318.85, 15300.65, 17560.18, 11702.82, 45361.85, 26931.03, 19632.26, 19669.56, 53210.28, 11720.87, 2522.66, 10011.37, 21026.68, 5701.84, 8893.12, 605.83, 12512.3, 5020.37, 1670.44, 2102.21, 6610.05], + 2010: [14113.58, 9224.46, 20394.26, 9200.86, 11672, 18457.27, 8667.58, 10368.6, 17165.98, 41425.48, 27722.31, 12359.33, 14737.12, 9451.26, 39169.92, 23092.36, 15967.61, 16037.96, 46013.06, 9569.85, 2064.5, 7925.58, 17185.48, 4602.16, 7224.18, 507.46, 10123.48, 4120.75, 1350.43, 1689.65, 5437.47], + 2009: [12153.03, 7521.85, 17235.48, 7358.31, 9740.25, 15212.49, 7278.75, 8587, 15046.45, 34457.3, 22990.35, 10062.82, 12236.53, 7655.18, 33896.65, 19480.46, 12961.1, 13059.69, 39482.56, 7759.16, 1654.21, 6530.01, 14151.28, 3912.68, 6169.75, 441.36, 8169.8, 3387.56, 1081.27, 1353.31, 4277.05], + 2008: [11115, 6719.01, 16011.97, 7315.4, 8496.2, 13668.58, 6426.1, 8314.37, 14069.87, 30981.98, 21462.69, 8851.66, 10823.01, 6971.05, 30933.28, 18018.53, 11328.92, 11555, 36796.71, 7021, 1503.06, 5793.66, 12601.23, 3561.56, 5692.12, 394.85, 7314.58, 3166.82, 1018.62, 1203.92, 4183.21], + 2007: [9846.81, 5252.76, 13607.32, 6024.45, 6423.18, 11164.3, 5284.69, 7104, 12494.01, 26018.48, 18753.73, 7360.92, 9248.53, 5800.25, 25776.91, 15012.46, 9333.4, 9439.6, 31777.01, 5823.41, 1254.17, 4676.13, 10562.39, 2884.11, 4772.52, 341.43, 5757.29, 2703.98, 797.35, 919.11, 3523.16], + 2006: [8117.78, 4462.74, 11467.6, 4878.61, 4944.25, 9304.52, 4275.12, 6211.8, 10572.24, 21742.05, 15718.47, 6112.5, 7583.85, 4820.53, 21900.19, 12362.79, 7617.47, 7688.67, 26587.76, 4746.16, 1065.67, 3907.23, 8690.24, 2338.98, 3988.14, 290.76, 4743.61, 2277.35, 648.5, 725.9, 3045.26], + 2005: [6969.52, 3905.64, 10012.11, 4230.53, 3905.03, 8047.26, 3620.27, 5513.7, 9247.66, 18598.69, 13417.68, 5350.17, 6554.69, 4056.76, 18366.87, 10587.42, 6590.19, 6596.1, 22557.37, 3984.1, 918.75, 3467.72, 7385.1, 2005.42, 3462.73, 248.8, 3933.72, 1933.98, 543.32, 612.61, 2604.19], + 2004: [6033.21, 3110.97, 8477.63, 3571.37, 3041.07, 6672, 3122.01, 4750.6, 8072.83, 15003.6, 11648.7, 4759.3, 5763.35, 3456.7, 15021.84, 8553.79, 5633.24, 5641.94, 18864.62, 3433.5, 819.66, 3034.58, 6379.63, 1677.8, 3081.91, 220.34, 3175.58, 1688.49, 466.1, 537.11, 2209.09], + 2003: [5007.21, 2578.03, 6921.29, 2855.23, 2388.38, 6002.54, 2662.08, 4057.4, 6694.23, 12442.87, 9705.02, 3923.11, 4983.67, 2807.41, 12078.15, 6867.7, 4757.45, 4659.99, 15844.64, 2821.11, 713.96, 2555.72, 5333.09, 1426.34, 2556.02, 185.09, 2587.72, 1399.83, 390.2, 445.36, 1886.35], + 2002: [4315, 2150.76, 6018.28, 2324.8, 1940.94, 5458.22, 2348.54, 3637.2, 5741.03, 10606.85, 8003.67, 3519.72, 4467.55, 2450.48, 10275.5, 6035.48, 4212.82, 4151.54, 13502.42, 2523.73, 642.73, 2232.86, 4725.01, 1243.43, 2312.82, 162.04, 2253.39, 1232.03, 340.65, 377.16, 1612.6] + }) + + dataMap.dataPI = dataFormatter({ + 2011: [136.27, 159.72, 2905.73, 641.42, 1306.3, 1915.57, 1277.44, 1701.5, 124.94, 3064.78, 1583.04, 2015.31, 1612.24, 1391.07, 3973.85, 3512.24, 2569.3, 2768.03, 2665.2, 2047.23, 659.23, 844.52, 2983.51, 726.22, 1411.01, 74.47, 1220.9, 678.75, 155.08, 184.14, 1139.03], + 2010: [124.36, 145.58, 2562.81, 554.48, 1095.28, 1631.08, 1050.15, 1302.9, 114.15, 2540.1, 1360.56, 1729.02, 1363.67, 1206.98, 3588.28, 3258.09, 2147, 2325.5, 2286.98, 1675.06, 539.83, 685.38, 2482.89, 625.03, 1108.38, 68.72, 988.45, 599.28, 134.92, 159.29, 1078.63], + 2009: [118.29, 128.85, 2207.34, 477.59, 929.6, 1414.9, 980.57, 1154.33, 113.82, 2261.86, 1163.08, 1495.45, 1182.74, 1098.66, 3226.64, 2769.05, 1795.9, 1969.69, 2010.27, 1458.49, 462.19, 606.8, 2240.61, 550.27, 1067.6, 63.88, 789.64, 497.05, 107.4, 127.25, 759.74], + 2008: [112.83, 122.58, 2034.59, 313.58, 907.95, 1302.02, 916.72, 1088.94, 111.8, 2100.11, 1095.96, 1418.09, 1158.17, 1060.38, 3002.65, 2658.78, 1780, 1892.4, 1973.05, 1453.75, 436.04, 575.4, 2216.15, 539.19, 1020.56, 60.62, 753.72, 462.27, 105.57, 118.94, 691.07], + 2007: [101.26, 110.19, 1804.72, 311.97, 762.1, 1133.42, 783.8, 915.38, 101.84, 1816.31, 986.02, 1200.18, 1002.11, 905.77, 2509.14, 2217.66, 1378, 1626.48, 1695.57, 1241.35, 361.07, 482.39, 2032, 446.38, 837.35, 54.89, 592.63, 387.55, 83.41, 97.89, 628.72], + 2006: [88.8, 103.35, 1461.81, 276.77, 634.94, 939.43, 672.76, 750.14, 93.81, 1545.05, 925.1, 1011.03, 865.98, 786.14, 2138.9, 1916.74, 1140.41, 1272.2, 1532.17, 1032.47, 323.48, 386.38, 1595.48, 382.06, 724.4, 50.9, 484.81, 334, 67.55, 79.54, 527.8], + 2005: [88.68, 112.38, 1400, 262.42, 589.56, 882.41, 625.61, 684.6, 90.26, 1461.51, 892.83, 966.5, 827.36, 727.37, 1963.51, 1892.01, 1082.13, 1100.65, 1428.27, 912.5, 300.75, 463.4, 1481.14, 368.94, 661.69, 48.04, 435.77, 308.06, 65.34, 72.07, 509.99], + 2004: [87.36, 105.28, 1370.43, 276.3, 522.8, 798.43, 568.69, 605.79, 83.45, 1367.58, 814.1, 950.5, 786.84, 664.5, 1778.45, 1649.29, 1020.09, 1022.45, 1248.59, 817.88, 278.76, 428.05, 1379.93, 334.5, 607.75, 44.3, 387.88, 286.78, 60.7, 65.33, 461.26], + 2003: [84.11, 89.91, 1064.05, 215.19, 420.1, 615.8, 488.23, 504.8, 81.02, 1162.45, 717.85, 749.4, 692.94, 560, 1480.67, 1198.7, 798.35, 886.47, 1072.91, 658.78, 244.29, 339.06, 1128.61, 298.69, 494.6, 40.7, 302.66, 237.91, 48.47, 55.63, 412.9], + 2002: [82.44, 84.21, 956.84, 197.8, 374.69, 590.2, 446.17, 474.2, 79.68, 1110.44, 685.2, 783.66, 664.78, 535.98, 1390, 1288.36, 707, 847.25, 1015.08, 601.99, 222.89, 317.87, 1047.95, 281.1, 463.44, 39.75, 282.21, 215.51, 47.31, 52.95, 305] + }) + + dataMap.dataSI = dataFormatter({ + 2011: [3752.48, 5928.32, 13126.86, 6635.26, 8037.69, 12152.15, 5611.48, 5962.41, 7927.89, 25203.28, 16555.58, 8309.38, 9069.2, 6390.55, 24017.11, 15427.08, 9815.94, 9361.99, 26447.38, 5675.32, 714.5, 5543.04, 11029.13, 2194.33, 3780.32, 208.79, 6935.59, 2377.83, 975.18, 1056.15, 3225.9], + 2010: [3388.38, 4840.23, 10707.68, 5234, 6367.69, 9976.82, 4506.31, 5025.15, 7218.32, 21753.93, 14297.93, 6436.62, 7522.83, 5122.88, 21238.49, 13226.38, 7767.24, 7343.19, 23014.53, 4511.68, 571, 4359.12, 8672.18, 1800.06, 3223.49, 163.92, 5446.1, 1984.97, 744.63, 827.91, 2592.15], + 2009: [2855.55, 3987.84, 8959.83, 3993.8, 5114, 7906.34, 3541.92, 4060.72, 6001.78, 18566.37, 11908.49, 4905.22, 6005.3, 3919.45, 18901.83, 11010.5, 6038.08, 5687.19, 19419.7, 3381.54, 443.43, 3448.77, 6711.87, 1476.62, 2582.53, 136.63, 4236.42, 1527.24, 575.33, 662.32, 1929.59], + 2008: [2626.41, 3709.78, 8701.34, 4242.36, 4376.19, 7158.84, 3097.12, 4319.75, 6085.84, 16993.34, 11567.42, 4198.93, 5318.44, 3554.81, 17571.98, 10259.99, 5082.07, 5028.93, 18502.2, 3037.74, 423.55, 3057.78, 5823.39, 1370.03, 2452.75, 115.56, 3861.12, 1470.34, 557.12, 609.98, 2070.76], + 2007: [2509.4, 2892.53, 7201.88, 3454.49, 3193.67, 5544.14, 2475.45, 3695.58, 5571.06, 14471.26, 10154.25, 3370.96, 4476.42, 2975.53, 14647.53, 8282.83, 4143.06, 3977.72, 16004.61, 2425.29, 364.26, 2368.53, 4648.79, 1124.79, 2038.39, 98.48, 2986.46, 1279.32, 419.03, 455.04, 1647.55], + 2006: [2191.43, 2457.08, 6110.43, 2755.66, 2374.96, 4566.83, 1915.29, 3365.31, 4969.95, 12282.89, 8511.51, 2711.18, 3695.04, 2419.74, 12574.03, 6724.61, 3365.08, 3187.05, 13469.77, 1878.56, 308.62, 1871.65, 3775.14, 967.54, 1705.83, 80.1, 2452.44, 1043.19, 331.91, 351.58, 1459.3], + 2005: [2026.51, 2135.07, 5271.57, 2357.04, 1773.21, 3869.4, 1580.83, 2971.68, 4381.2, 10524.96, 7164.75, 2245.9, 3175.92, 1917.47, 10478.62, 5514.14, 2852.12, 2612.57, 11356.6, 1510.68, 240.83, 1564, 3067.23, 821.16, 1426.42, 63.52, 1951.36, 838.56, 264.61, 281.05, 1164.79], + 2004: [1853.58, 1685.93, 4301.73, 1919.4, 1248.27, 3061.62, 1329.68, 2487.04, 3892.12, 8437.99, 6250.38, 1844.9, 2770.49, 1566.4, 8478.69, 4182.1, 2320.6, 2190.54, 9280.73, 1253.7, 205.6, 1376.91, 2489.4, 681.5, 1281.63, 52.74, 1553.1, 713.3, 211.7, 244.05, 914.47], + 2003: [1487.15, 1337.31, 3417.56, 1463.38, 967.49, 2898.89, 1098.37, 2084.7, 3209.02, 6787.11, 5096.38, 1535.29, 2340.82, 1204.33, 6485.05, 3310.14, 1956.02, 1777.74, 7592.78, 984.08, 175.82, 1135.31, 2014.8, 569.37, 1047.66, 47.64, 1221.17, 572.02, 171.92, 194.27, 719.54], + 2002: [1249.99, 1069.08, 2911.69, 1134.31, 754.78, 2609.85, 943.49, 1843.6, 2622.45, 5604.49, 4090.48, 1337.04, 2036.97, 941.77, 5184.98, 2768.75, 1709.89, 1523.5, 6143.4, 846.89, 148.88, 958.87, 1733.38, 481.96, 934.88, 32.72, 1007.56, 501.69, 144.51, 153.06, 603.15] + }) + + dataMap.dataTI = dataFormatter({ + 2011: [12363.18, 5219.24, 8483.17, 3960.87, 5015.89, 8158.98, 3679.91, 4918.09, 11142.86, 20842.21, 14180.23, 4975.96, 6878.74, 3921.2, 17370.89, 7991.72, 7247.02, 7539.54, 24097.7, 3998.33, 1148.93, 3623.81, 7014.04, 2781.29, 3701.79, 322.57, 4355.81, 1963.79, 540.18, 861.92, 2245.12], + 2010: [10600.84, 4238.65, 7123.77, 3412.38, 4209.03, 6849.37, 3111.12, 4040.55, 9833.51, 17131.45, 12063.82, 4193.69, 5850.62, 3121.4, 14343.14, 6607.89, 6053.37, 6369.27, 20711.55, 3383.11, 953.67, 2881.08, 6030.41, 2177.07, 2892.31, 274.82, 3688.93, 1536.5, 470.88, 702.45, 1766.69], + 2009: [9179.19, 3405.16, 6068.31, 2886.92, 3696.65, 5891.25, 2756.26, 3371.95, 8930.85, 13629.07, 9918.78, 3662.15, 5048.49, 2637.07, 11768.18, 5700.91, 5127.12, 5402.81, 18052.59, 2919.13, 748.59, 2474.44, 5198.8, 1885.79, 2519.62, 240.85, 3143.74, 1363.27, 398.54, 563.74, 1587.72], + 2008: [8375.76, 2886.65, 5276.04, 2759.46, 3212.06, 5207.72, 2412.26, 2905.68, 7872.23, 11888.53, 8799.31, 3234.64, 4346.4, 2355.86, 10358.64, 5099.76, 4466.85, 4633.67, 16321.46, 2529.51, 643.47, 2160.48, 4561.69, 1652.34, 2218.81, 218.67, 2699.74, 1234.21, 355.93, 475, 1421.38], + 2007: [7236.15, 2250.04, 4600.72, 2257.99, 2467.41, 4486.74, 2025.44, 2493.04, 6821.11, 9730.91, 7613.46, 2789.78, 3770, 1918.95, 8620.24, 4511.97, 3812.34, 3835.4, 14076.83, 2156.76, 528.84, 1825.21, 3881.6, 1312.94, 1896.78, 188.06, 2178.2, 1037.11, 294.91, 366.18, 1246.89], + 2006: [5837.55, 1902.31, 3895.36, 1846.18, 1934.35, 3798.26, 1687.07, 2096.35, 5508.48, 7914.11, 6281.86, 2390.29, 3022.83, 1614.65, 7187.26, 3721.44, 3111.98, 3229.42, 11585.82, 1835.12, 433.57, 1649.2, 3319.62, 989.38, 1557.91, 159.76, 1806.36, 900.16, 249.04, 294.78, 1058.16], + 2005: [4854.33, 1658.19, 3340.54, 1611.07, 1542.26, 3295.45, 1413.83, 1857.42, 4776.2, 6612.22, 5360.1, 2137.77, 2551.41, 1411.92, 5924.74, 3181.27, 2655.94, 2882.88, 9772.5, 1560.92, 377.17, 1440.32, 2836.73, 815.32, 1374.62, 137.24, 1546.59, 787.36, 213.37, 259.49, 929.41], + 2004: [4092.27, 1319.76, 2805.47, 1375.67, 1270, 2811.95, 1223.64, 1657.77, 4097.26, 5198.03, 4584.22, 1963.9, 2206.02, 1225.8, 4764.7, 2722.4, 2292.55, 2428.95, 8335.3, 1361.92, 335.3, 1229.62, 2510.3, 661.8, 1192.53, 123.3, 1234.6, 688.41, 193.7, 227.73, 833.36], + 2003: [3435.95, 1150.81, 2439.68, 1176.65, 1000.79, 2487.85, 1075.48, 1467.9, 3404.19, 4493.31, 3890.79, 1638.42, 1949.91, 1043.08, 4112.43, 2358.86, 2003.08, 1995.78, 7178.94, 1178.25, 293.85, 1081.35, 2189.68, 558.28, 1013.76, 96.76, 1063.89, 589.91, 169.81, 195.46, 753.91], + 2002: [2982.57, 997.47, 2149.75, 992.69, 811.47, 2258.17, 958.88, 1319.4, 3038.9, 3891.92, 3227.99, 1399.02, 1765.8, 972.73, 3700.52, 1978.37, 1795.93, 1780.79, 6343.94, 1074.85, 270.96, 956.12, 1943.68, 480.37, 914.5, 89.56, 963.62, 514.83, 148.83, 171.14, 704.5] + }) + + dataMap.dataEstate = dataFormatter({ + 2011: [1074.93, 411.46, 918.02, 224.91, 384.76, 876.12, 238.61, 492.1, 1019.68, 2747.89, 1677.13, 634.92, 911.16, 402.51, 1838.14, 987, 634.67, 518.04, 3321.31, 465.68, 208.71, 396.28, 620.62, 160.3, 222.31, 17.44, 398.03, 134.25, 29.05, 79.01, 176.22], + 2010: [1006.52, 377.59, 697.79, 192, 309.25, 733.37, 212.32, 391.89, 1002.5, 2600.95, 1618.17, 532.17, 679.03, 340.56, 1622.15, 773.23, 564.41, 464.21, 2813.95, 405.79, 188.33, 266.38, 558.56, 139.64, 223.45, 14.54, 315.95, 110.02, 25.41, 60.53, 143.44], + 2009: [1062.47, 308.73, 612.4, 173.31, 286.65, 605.27, 200.14, 301.18, 1237.56, 2025.39, 1316.84, 497.94, 656.61, 305.9, 1329.59, 622.98, 546.11, 400.11, 2470.63, 348.98, 121.76, 229.09, 548.14, 136.15, 205.14, 13.28, 239.92, 101.37, 23.05, 47.56, 115.23], + 2008: [844.59, 227.88, 513.81, 166.04, 273.3, 500.81, 182.7, 244.47, 939.34, 1626.13, 1052.03, 431.27, 506.98, 281.96, 1104.95, 512.42, 526.88, 340.07, 2057.45, 282.96, 95.6, 191.21, 453.63, 104.81, 195.48, 15.08, 193.27, 93.8, 19.96, 38.85, 89.79], + 2007: [821.5, 183.44, 467.97, 134.12, 191.01, 410.43, 153.03, 225.81, 958.06, 1365.71, 981.42, 366.57, 511.5, 225.96, 953.69, 447.44, 409.65, 301.8, 2029.77, 239.45, 67.19, 196.06, 376.84, 93.19, 193.59, 13.24, 153.98, 83.52, 16.98, 29.49, 91.28], + 2006: [658.3, 156.64, 397.14, 117.01, 136.5, 318.54, 131.01, 194.7, 773.61, 1017.91, 794.41, 281.98, 435.22, 184.67, 786.51, 348.7, 294.73, 254.81, 1722.07, 192.2, 44.45, 158.2, 336.2, 80.24, 165.92, 11.92, 125.2, 73.21, 15.17, 25.53, 68.9], + 2005: [493.73, 122.67, 330.87, 106, 98.75, 256.77, 112.29, 163.34, 715.97, 799.73, 688.86, 231.66, 331.8, 171.88, 664.9, 298.19, 217.17, 215.63, 1430.37, 165.05, 38.2, 143.88, 286.23, 76.38, 148.69, 10.02, 108.62, 63.78, 14.1, 22.97, 55.79], + 2004: [436.11, 106.14, 231.08, 95.1, 73.81, 203.1, 97.93, 137.74, 666.3, 534.17, 587.83, 188.28, 248.44, 167.2, 473.27, 236.44, 204.8, 191.5, 1103.75, 122.52, 30.64, 129.12, 264.3, 68.3, 116.54, 5.8, 95.9, 56.84, 13, 20.78, 53.55], + 2003: [341.88, 92.31, 185.19, 78.73, 61.05, 188.49, 91.99, 127.2, 487.82, 447.47, 473.16, 162.63, 215.84, 138.02, 418.21, 217.58, 176.8, 186.49, 955.66, 100.93, 25.14, 113.69, 231.72, 59.86, 103.79, 4.35, 83.9, 48.09, 11.41, 16.85, 47.84], + 2002: [298.02, 73.04, 140.89, 65.83, 51.48, 130.94, 76.11, 118.7, 384.86, 371.09, 360.63, 139.18, 188.09, 125.27, 371.13, 199.31, 145.17, 165.29, 808.16, 82.83, 21.45, 90.48, 210.82, 53.49, 95.68, 3.42, 77.68, 41.52, 9.74, 13.46, 43.04] + }) + + dataMap.dataFinancial = dataFormatter({ + 2011: [2215.41, 756.5, 746.01, 519.32, 447.46, 755.57, 207.65, 370.78, 2277.4, 2600.11, 2730.29, 503.85, 862.41, 357.44, 1640.41, 868.2, 674.57, 501.09, 2916.13, 445.37, 105.24, 704.66, 868.15, 297.27, 456.23, 31.7, 432.11, 145.05, 62.56, 134.18, 288.77], + 2010: [1863.61, 572.99, 615.42, 448.3, 346.44, 639.27, 190.12, 304.59, 1950.96, 2105.92, 2326.58, 396.17, 767.58, 241.49, 1361.45, 697.68, 561.27, 463.16, 2658.76, 384.53, 78.12, 496.56, 654.7, 231.51, 375.08, 27.08, 384.75, 100.54, 54.53, 97.87, 225.2], + 2009: [1603.63, 461.2, 525.67, 361.64, 291.1, 560.2, 180.83, 227.54, 1804.28, 1596.98, 1899.33, 359.6, 612.2, 165.1, 1044.9, 499.92, 479.11, 402.57, 2283.29, 336.82, 65.73, 389.97, 524.63, 194.44, 351.74, 23.17, 336.21, 88.27, 45.63, 75.54, 198.87], + 2008: [1519.19, 368.1, 420.74, 290.91, 219.09, 455.07, 147.24, 177.43, 1414.21, 1298.48, 1653.45, 313.81, 497.65, 130.57, 880.28, 413.83, 393.05, 334.32, 1972.4, 249.01, 47.33, 303.01, 411.14, 151.55, 277.66, 22.42, 287.16, 72.49, 36.54, 64.8, 171.97], + 2007: [1302.77, 288.17, 347.65, 218.73, 148.3, 386.34, 126.03, 155.48, 1209.08, 1054.25, 1251.43, 223.85, 385.84, 101.34, 734.9, 302.31, 337.27, 260.14, 1705.08, 190.73, 34.43, 247.46, 359.11, 122.25, 168.55, 11.51, 231.03, 61.6, 27.67, 51.05, 149.22], + 2006: [982.37, 186.87, 284.04, 169.63, 108.21, 303.41, 100.75, 74.17, 825.2, 653.25, 906.37, 166.01, 243.9, 79.75, 524.94, 219.72, 174.99, 204.72, 899.91, 129.14, 16.37, 213.7, 299.5, 89.43, 143.62, 6.44, 152.25, 50.51, 23.69, 36.99, 99.25], + 2005: [840.2, 147.4, 213.47, 135.07, 72.52, 232.85, 83.63, 35.03, 675.12, 492.4, 686.32, 127.05, 186.12, 69.55, 448.36, 181.74, 127.32, 162.37, 661.81, 91.93, 13.16, 185.18, 262.26, 73.67, 130.5, 7.57, 127.58, 44.73, 20.36, 32.25, 80.34], + 2004: [713.79, 136.97, 209.1, 110.29, 55.89, 188.04, 77.17, 32.2, 612.45, 440.5, 523.49, 94.1, 171, 65.1, 343.37, 170.82, 118.85, 118.64, 602.68, 74, 11.56, 162.38, 236.5, 60.3, 118.4, 5.4, 90.1, 42.99, 19, 27.92, 70.3], + 2003: [635.56, 112.79, 199.87, 118.48, 55.89, 145.38, 73.15, 32.2, 517.97, 392.11, 451.54, 87.45, 150.09, 64.31, 329.71, 165.11, 107.31, 99.35, 534.28, 61.59, 10.68, 147.04, 206.24, 48.01, 105.48, 4.74, 77.87, 42.31, 17.98, 24.8, 64.92], + 2002: [561.91, 76.86, 179.6, 124.1, 48.39, 137.18, 75.45, 31.6, 485.25, 368.86, 347.53, 81.85, 138.28, 76.51, 310.07, 158.77, 96.95, 92.43, 454.65, 35.86, 10.08, 134.52, 183.13, 41.45, 102.39, 2.81, 67.3, 42.08, 16.75, 21.45, 52.18] + }) + + this.chart.setOption({ + baseOption: { + timeline: { + axisType: 'category', + autoPlay: true, + playInterval: 1000, + data: [ + '2002-01-01', '2003-01-01', '2004-01-01', + { + value: '2005-01-01', + tooltip: { + formatter: '{b} GDP达到一个高度' + }, + symbol: 'diamond', + symbolSize: 16 + }, + '2006-01-01', '2007-01-01', '2008-01-01', '2009-01-01', '2010-01-01', + { + value: '2011-01-01', + tooltip: { + formatter: function(params) { + return params.name + 'GDP达到又一个高度' + } + }, + symbol: 'diamond', + symbolSize: 18 + } + ], + label: { + formatter: function(s) { + return (new Date(s)).getFullYear() + } + } + }, + title: { + subtext: '数据来自国家统计局' + }, + tooltip: {}, + legend: { + x: 'right', + data: ['第一产业', '第二产业', '第三产业', 'GDP', '金融', '房地产'], + selected: { + 'GDP': false, '金融': false, '房地产': false + } + }, + calculable: true, + grid: { + top: 80, + bottom: 100, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow', + label: { + show: true, + formatter: function(params) { + return params.value.replace('\n', '') + } + } + } + } + }, + xAxis: [ + { + 'type': 'category', + 'axisLabel': { + 'interval': 0, + rotate: 45 + }, + 'data': [ + '北京', '\n天津', '河北', '\n山西', '内蒙古', '\n辽宁', '吉林', '\n黑龙江', + '上海', '\n江苏', '浙江', '\n安徽', '福建', '\n江西', '山东', '\n河南', + '湖北', '\n湖南', '广东', '\n广西', '海南', '\n重庆', '四川', '\n贵州', + '云南', '\n西藏', '陕西', '\n甘肃', '青海', '\n宁夏', '新疆' + ], + splitLine: { show: false } + } + ], + yAxis: [ + { + type: 'value', + name: 'GDP(亿元)' + } + ], + series: [ + { name: 'GDP', type: 'bar' }, + { name: '金融', type: 'bar' }, + { name: '房地产', type: 'bar' }, + { name: '第一产业', type: 'bar' }, + { name: '第二产业', type: 'bar' }, + { name: '第三产业', type: 'bar' }, + { + name: 'GDP占比', + type: 'pie', + center: ['75%', '35%'], + radius: '28%', + z: 100 + } + ] + }, + options: [ + { + title: { text: '2002全国宏观经济指标' }, + series: [ + { data: dataMap.dataGDP['2002'] }, + { data: dataMap.dataFinancial['2002'] }, + { data: dataMap.dataEstate['2002'] }, + { data: dataMap.dataPI['2002'] }, + { data: dataMap.dataSI['2002'] }, + { data: dataMap.dataTI['2002'] }, + { + data: [ + { name: '第一产业', value: dataMap.dataPI['2002sum'] }, + { name: '第二产业', value: dataMap.dataSI['2002sum'] }, + { name: '第三产业', value: dataMap.dataTI['2002sum'] } + ] + } + ] + }, + { + title: { text: '2003全国宏观经济指标' }, + series: [ + { data: dataMap.dataGDP['2003'] }, + { data: dataMap.dataFinancial['2003'] }, + { data: dataMap.dataEstate['2003'] }, + { data: dataMap.dataPI['2003'] }, + { data: dataMap.dataSI['2003'] }, + { data: dataMap.dataTI['2003'] }, + { + data: [ + { name: '第一产业', value: dataMap.dataPI['2003sum'] }, + { name: '第二产业', value: dataMap.dataSI['2003sum'] }, + { name: '第三产业', value: dataMap.dataTI['2003sum'] } + ] + } + ] + }, + { + title: { text: '2004全国宏观经济指标' }, + series: [ + { data: dataMap.dataGDP['2004'] }, + { data: dataMap.dataFinancial['2004'] }, + { data: dataMap.dataEstate['2004'] }, + { data: dataMap.dataPI['2004'] }, + { data: dataMap.dataSI['2004'] }, + { data: dataMap.dataTI['2004'] }, + { + data: [ + { name: '第一产业', value: dataMap.dataPI['2004sum'] }, + { name: '第二产业', value: dataMap.dataSI['2004sum'] }, + { name: '第三产业', value: dataMap.dataTI['2004sum'] } + ] + } + ] + }, + { + title: { text: '2005全国宏观经济指标' }, + series: [ + { data: dataMap.dataGDP['2005'] }, + { data: dataMap.dataFinancial['2005'] }, + { data: dataMap.dataEstate['2005'] }, + { data: dataMap.dataPI['2005'] }, + { data: dataMap.dataSI['2005'] }, + { data: dataMap.dataTI['2005'] }, + { + data: [ + { name: '第一产业', value: dataMap.dataPI['2005sum'] }, + { name: '第二产业', value: dataMap.dataSI['2005sum'] }, + { name: '第三产业', value: dataMap.dataTI['2005sum'] } + ] + } + ] + }, + { + title: { text: '2006全国宏观经济指标' }, + series: [ + { data: dataMap.dataGDP['2006'] }, + { data: dataMap.dataFinancial['2006'] }, + { data: dataMap.dataEstate['2006'] }, + { data: dataMap.dataPI['2006'] }, + { data: dataMap.dataSI['2006'] }, + { data: dataMap.dataTI['2006'] }, + { + data: [ + { name: '第一产业', value: dataMap.dataPI['2006sum'] }, + { name: '第二产业', value: dataMap.dataSI['2006sum'] }, + { name: '第三产业', value: dataMap.dataTI['2006sum'] } + ] + } + ] + }, + { + title: { text: '2007全国宏观经济指标' }, + series: [ + { data: dataMap.dataGDP['2007'] }, + { data: dataMap.dataFinancial['2007'] }, + { data: dataMap.dataEstate['2007'] }, + { data: dataMap.dataPI['2007'] }, + { data: dataMap.dataSI['2007'] }, + { data: dataMap.dataTI['2007'] }, + { + data: [ + { name: '第一产业', value: dataMap.dataPI['2007sum'] }, + { name: '第二产业', value: dataMap.dataSI['2007sum'] }, + { name: '第三产业', value: dataMap.dataTI['2007sum'] } + ] + } + ] + }, + { + title: { text: '2008全国宏观经济指标' }, + series: [ + { data: dataMap.dataGDP['2008'] }, + { data: dataMap.dataFinancial['2008'] }, + { data: dataMap.dataEstate['2008'] }, + { data: dataMap.dataPI['2008'] }, + { data: dataMap.dataSI['2008'] }, + { data: dataMap.dataTI['2008'] }, + { + data: [ + { name: '第一产业', value: dataMap.dataPI['2008sum'] }, + { name: '第二产业', value: dataMap.dataSI['2008sum'] }, + { name: '第三产业', value: dataMap.dataTI['2008sum'] } + ] + } + ] + }, + { + title: { text: '2009全国宏观经济指标' }, + series: [ + { data: dataMap.dataGDP['2009'] }, + { data: dataMap.dataFinancial['2009'] }, + { data: dataMap.dataEstate['2009'] }, + { data: dataMap.dataPI['2009'] }, + { data: dataMap.dataSI['2009'] }, + { data: dataMap.dataTI['2009'] }, + { + data: [ + { name: '第一产业', value: dataMap.dataPI['2009sum'] }, + { name: '第二产业', value: dataMap.dataSI['2009sum'] }, + { name: '第三产业', value: dataMap.dataTI['2009sum'] } + ] + } + ] + }, + { + title: { text: '2010全国宏观经济指标' }, + series: [ + { data: dataMap.dataGDP['2010'] }, + { data: dataMap.dataFinancial['2010'] }, + { data: dataMap.dataEstate['2010'] }, + { data: dataMap.dataPI['2010'] }, + { data: dataMap.dataSI['2010'] }, + { data: dataMap.dataTI['2010'] }, + { + data: [ + { name: '第一产业', value: dataMap.dataPI['2010sum'] }, + { name: '第二产业', value: dataMap.dataSI['2010sum'] }, + { name: '第三产业', value: dataMap.dataTI['2010sum'] } + ] + } + ] + }, + { + title: { text: '2011全国宏观经济指标' }, + series: [ + { data: dataMap.dataGDP['2011'] }, + { data: dataMap.dataFinancial['2011'] }, + { data: dataMap.dataEstate['2011'] }, + { data: dataMap.dataPI['2011'] }, + { data: dataMap.dataSI['2011'] }, + { data: dataMap.dataTI['2011'] }, + { + data: [ + { name: '第一产业', value: dataMap.dataPI['2011sum'] }, + { name: '第二产业', value: dataMap.dataSI['2011sum'] }, + { name: '第三产业', value: dataMap.dataTI['2011sum'] } + ] + } + ] + } + ] + }) + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Egressdns.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Egressdns.vue new file mode 100644 index 0000000..a7ec7a7 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Egressdns.vue @@ -0,0 +1,166 @@ +<template> + <div class="wrapper"> + <div id="chart3" class="chart" /> + </div> +</template> + +<script> +import echarts from 'echarts' +export default { + props: ['do53egressdns'], + data() { + return {} + }, + mounted() { + this.getWorld(this.do53egressdns) + var myChartContainer = document.getElementById('chart3') + // 获取自适应的高度和宽度 + var resizeMyChartContainer = function() { + // myChartContainer.style.height = window.innerHeight * 0.65 + 'px'; + // myChartContainer.style.width = window.innerWidth * 0.75 + 'px'; + myChartContainer.style.height = 300 + 'px' + myChartContainer.style.width = 600 + 'px' + if (window.innerWidth > 768 && window.innerWidth < 1370) { + myChartContainer.style.width = 500 + 'px' + } + } + // 设置容器高和宽 + resizeMyChartContainer() + var myChart = echarts.init(myChartContainer) + const option = {} + myChart.setOption(option) + }, + methods: { + changeKey(arr, key) { + const newArr = [] + arr.forEach((item, index) => { + const newObj = {} + for (var i = 0; i < key.length; i++) { + newObj[key[i]] = item[Object.keys(item)[i]] + } + newArr.push(newObj) + }) + return newArr + }, + getWorld(data) { + const list = this.changeKey(this.do53egressdns, ['name', 'value']) + var that = this + // const {ctx} = getCurrentInstance() + this.$axios.get('/sjData/word.json').then(function(res) { + // console.log(list,111); + const namemap = res.data.namemap + const dataArr = list + // let dataArr = data.data + that.drawChart(namemap, dataArr) + }) + }, + drawChart(name, data) { + // 基于准备好的dom,初始化echarts实例 + const chart = echarts.init(document.getElementById('chart3')) + + // 监听屏幕变化自动缩放图表 + window.addEventListener('resize', function() { + chart.resize() + }) + // 绘制图表 + chart.setOption({ + // 图表主标题 + // title: { + // text: '世界地图', // 主标题文本,支持使用 \n 换行 + // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比 + // left: 'center', // 值: 'left', 'center', 'right' 同上 + // textStyle: { // 文本样式 + // fontSize: 24, + // fontWeight: 600, + // color: '#000' + // } + // }, + + grid: { + width: '100%', + height: '100%', + left: '0%', + right: '0%', + bottom: '0%', + containLabel: true + }, + // 提示框组件 + tooltip: { + trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用 + // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式 + // 使用函数模板 传入的数据值 -> value: number | Array + formatter: function(val) { + if (val.data == null) return + return val.data.name + ': ' + val.data.value + } + }, + // 视觉映射组件 + visualMap: { + min: 0, + max: 10000000, + text: ['max', 'min'], + realtime: false, + calculable: true, + color: ['#4608AD', '#d9e4ff'] + }, + series: [ + { + type: 'map', // 类型 + // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列 + name: '世界地图', + mapType: 'world', // 地图类型 + // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启 + roam: true, + // 图形上的文本标签 + label: { + show: false // 是否显示对应地名 + }, + zoom: 1.2, + // 地图区域的多边形 图形样式 + itemStyle: { + // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用 + borderWidth: 0.5, // 描边线宽 为 0 时无描边 + borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数 + borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted' + }, + // 高亮状态下的多边形和标签样式 + emphasis: { + label: { + show: true, // 是否显示标签 + color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色 + }, + itemStyle: { + areaColor: '#FF6347' // 地图区域的颜色 + } + }, + // 自定义地区的名称映射 + nameMap: name, + // 地图系列中的数据内容数组 数组项可以为单个数值 + data: data + } + ] + }) + } + } +} +</script> +<style lang="scss"> +.wrapper { + width: 100%; +} +.wrapper .chart1{ + width: 60%; + /* margin:0 auto; */ + height: 400px; + /* border: 1px solid #eeeeee; */ + /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/ + background-size: 100% 100%; + background-color: #fff; +} +.chart1 { + width: 100%; + height: 100%; + background-color: yellow; + +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Forwarder.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Forwarder.vue new file mode 100644 index 0000000..b660498 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Forwarder.vue @@ -0,0 +1,166 @@ +<template> + <div class="wrapper"> + <div id="chart2" class="chart" /> + </div> +</template> + +<script> +import echarts from 'echarts' +export default { + props: ['do53forwarder'], + data() { + return {} + }, + mounted() { + this.getWorld(this.do53forwarder) + var myChartContainer = document.getElementById('chart2') + // 获取自适应的高度和宽度 + var resizeMyChartContainer = function() { + // myChartContainer.style.height = window.innerHeight * 0.65 + 'px'; + // myChartContainer.style.width = window.innerWidth * 0.75 + 'px'; + myChartContainer.style.height = 300 + 'px' + myChartContainer.style.width = 600 + 'px' + if (window.innerWidth > 768 && window.innerWidth < 1370) { + myChartContainer.style.width = 500 + 'px' + } + } + // 设置容器高和宽 + resizeMyChartContainer() + var myChart = echarts.init(myChartContainer) + const option = {} + myChart.setOption(option) + }, + methods: { + changeKey(arr, key) { + const newArr = [] + arr.forEach((item, index) => { + const newObj = {} + for (var i = 0; i < key.length; i++) { + newObj[key[i]] = item[Object.keys(item)[i]] + } + newArr.push(newObj) + }) + return newArr + }, + getWorld(data) { + const list = this.changeKey(this.do53forwarder, ['name', 'value']) + var that = this + // const {ctx} = getCurrentInstance() + this.$axios.get('/sjData/word.json').then(function(res) { + // console.log(list,111); + const namemap = res.data.namemap + const dataArr = list + // let dataArr = data.data + that.drawChart(namemap, dataArr) + }) + }, + drawChart(name, data) { + // 基于准备好的dom,初始化echarts实例 + const chart = echarts.init(document.getElementById('chart2')) + + // 监听屏幕变化自动缩放图表 + window.addEventListener('resize', function() { + chart.resize() + }) + // 绘制图表 + chart.setOption({ + // 图表主标题 + // title: { + // text: '世界地图', // 主标题文本,支持使用 \n 换行 + // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比 + // left: 'center', // 值: 'left', 'center', 'right' 同上 + // textStyle: { // 文本样式 + // fontSize: 24, + // fontWeight: 600, + // color: '#000' + // } + // }, + + grid: { + width: '100%', + height: '100%', + left: '0%', + right: '0%', + bottom: '0%', + containLabel: true + }, + // 提示框组件 + tooltip: { + trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用 + // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式 + // 使用函数模板 传入的数据值 -> value: number | Array + formatter: function(val) { + if (val.data == null) return + return val.data.name + ': ' + val.data.value + } + }, + // 视觉映射组件 + visualMap: { + min: 0, + max: 10000, + text: ['max', 'min'], + realtime: false, + calculable: true, + color: ['#4608AD', '#d9e4ff'] + }, + series: [ + { + type: 'map', // 类型 + // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列 + name: '世界地图', + mapType: 'world', // 地图类型 + // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启 + roam: true, + // 图形上的文本标签 + label: { + show: false // 是否显示对应地名 + }, + zoom: 1.2, + // 地图区域的多边形 图形样式 + itemStyle: { + // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用 + borderWidth: 0.5, // 描边线宽 为 0 时无描边 + borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数 + borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted' + }, + // 高亮状态下的多边形和标签样式 + emphasis: { + label: { + show: true, // 是否显示标签 + color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色 + }, + itemStyle: { + areaColor: '#FF6347' // 地图区域的颜色 + } + }, + // 自定义地区的名称映射 + nameMap: name, + // 地图系列中的数据内容数组 数组项可以为单个数值 + data: data + } + ] + }) + } + } +} +</script> +<style lang="scss"> +.wrapper { + width: 100%; +} +.wrapper .chart1{ + width: 60%; + /* margin:0 auto; */ + height: 400px; + /* border: 1px solid #eeeeee; */ + /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/ + background-size: 100% 100%; + background-color: #fff; +} +.chart1 { + width: 100%; + height: 100%; + background-color: yellow; + +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Fwdrdns.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Fwdrdns.vue new file mode 100644 index 0000000..0be12ba --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Fwdrdns.vue @@ -0,0 +1,166 @@ +<template> + <div class="wrapper"> + <div id="chart4" class="chart" /> + </div> +</template> + +<script> +import echarts from 'echarts' +export default { + props: ['do53fwdrdns'], + data() { + return {} + }, + mounted() { + this.getWorld(this.do53fwdrdns) + var myChartContainer = document.getElementById('chart4') + // 获取自适应的高度和宽度 + var resizeMyChartContainer = function() { + // myChartContainer.style.height = window.innerHeight * 0.65 + 'px'; + // myChartContainer.style.width = window.innerWidth * 0.75 + 'px'; + myChartContainer.style.height = 300 + 'px' + myChartContainer.style.width = 600 + 'px' + if (window.innerWidth > 768 && window.innerWidth < 1370) { + myChartContainer.style.width = 500 + 'px' + } + } + // 设置容器高和宽 + resizeMyChartContainer() + var myChart = echarts.init(myChartContainer) + const option = {} + myChart.setOption(option) + }, + methods: { + changeKey(arr, key) { + const newArr = [] + arr.forEach((item, index) => { + const newObj = {} + for (var i = 0; i < key.length; i++) { + newObj[key[i]] = item[Object.keys(item)[i]] + } + newArr.push(newObj) + }) + return newArr + }, + getWorld(data) { + const list = this.changeKey(this.do53fwdrdns, ['name', 'value']) + var that = this + // const {ctx} = getCurrentInstance() + this.$axios.get('/sjData/word.json').then(function(res) { + // console.log(list,111); + const namemap = res.data.namemap + const dataArr = list + // let dataArr = data.data + that.drawChart(namemap, dataArr) + }) + }, + drawChart(name, data) { + // 基于准备好的dom,初始化echarts实例 + const chart = echarts.init(document.getElementById('chart4')) + + // 监听屏幕变化自动缩放图表 + window.addEventListener('resize', function() { + chart.resize() + }) + // 绘制图表 + chart.setOption({ + // 图表主标题 + // title: { + // text: '世界地图', // 主标题文本,支持使用 \n 换行 + // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比 + // left: 'center', // 值: 'left', 'center', 'right' 同上 + // textStyle: { // 文本样式 + // fontSize: 24, + // fontWeight: 600, + // color: '#000' + // } + // }, + + grid: { + width: '100%', + height: '100%', + left: '0%', + right: '0%', + bottom: '0%', + containLabel: true + }, + // 提示框组件 + tooltip: { + trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用 + // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式 + // 使用函数模板 传入的数据值 -> value: number | Array + formatter: function(val) { + if (val.data == null) return + return val.data.name + ': ' + val.data.value + } + }, + // 视觉映射组件 + visualMap: { + min: 0, + max: 10000, + text: ['max', 'min'], + realtime: false, + calculable: true, + color: ['#4608AD', '#d9e4ff'] + }, + series: [ + { + type: 'map', // 类型 + // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列 + name: '世界地图', + mapType: 'world', // 地图类型 + // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启 + roam: true, + // 图形上的文本标签 + label: { + show: false // 是否显示对应地名 + }, + zoom: 1.2, + // 地图区域的多边形 图形样式 + itemStyle: { + // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用 + borderWidth: 0.5, // 描边线宽 为 0 时无描边 + borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数 + borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted' + }, + // 高亮状态下的多边形和标签样式 + emphasis: { + label: { + show: true, // 是否显示标签 + color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色 + }, + itemStyle: { + areaColor: '#FF6347' // 地图区域的颜色 + } + }, + // 自定义地区的名称映射 + nameMap: name, + // 地图系列中的数据内容数组 数组项可以为单个数值 + data: data + } + ] + }) + } + } +} +</script> +<style lang="scss"> +.wrapper { + width: 100%; +} +.wrapper .chart1{ + width: 60%; + /* margin:0 auto; */ + height: 400px; + /* border: 1px solid #eeeeee; */ + /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/ + background-size: 100% 100%; + background-color: #fff; +} +.chart1 { + width: 100%; + height: 100%; + background-color: yellow; + +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Nonstandard.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Nonstandard.vue new file mode 100644 index 0000000..7e5cc9b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Nonstandard.vue @@ -0,0 +1,166 @@ +<template> + <div class="wrapper"> + <div id="chart6" class="chart" /> + </div> +</template> + +<script> +import echarts from 'echarts' +export default { + props: ['do53nonstandard'], + data() { + return {} + }, + mounted() { + this.getWorld(this.do53nonstandard) + var myChartContainer = document.getElementById('chart6') + // 获取自适应的高度和宽度 + var resizeMyChartContainer = function() { + // myChartContainer.style.height = window.innerHeight * 0.65 + 'px'; + // myChartContainer.style.width = window.innerWidth * 0.75 + 'px'; + myChartContainer.style.height = 300 + 'px' + myChartContainer.style.width = 600 + 'px' + if (window.innerWidth > 768 && window.innerWidth < 1370) { + myChartContainer.style.width = 500 + 'px' + } + } + // 设置容器高和宽 + resizeMyChartContainer() + var myChart = echarts.init(myChartContainer) + const option = {} + myChart.setOption(option) + }, + methods: { + changeKey(arr, key) { + const newArr = [] + arr.forEach((item, index) => { + const newObj = {} + for (var i = 0; i < key.length; i++) { + newObj[key[i]] = item[Object.keys(item)[i]] + } + newArr.push(newObj) + }) + return newArr + }, + getWorld(data) { + const list = this.changeKey(this.do53nonstandard, ['name', 'value']) + var that = this + // const {ctx} = getCurrentInstance() + this.$axios.get('/sjData/word.json').then(function(res) { + // console.log(list,111); + const namemap = res.data.namemap + const dataArr = list + // let dataArr = data.data + that.drawChart(namemap, dataArr) + }) + }, + drawChart(name, data) { + // 基于准备好的dom,初始化echarts实例 + const chart = echarts.init(document.getElementById('chart6')) + + // 监听屏幕变化自动缩放图表 + window.addEventListener('resize', function() { + chart.resize() + }) + // 绘制图表 + chart.setOption({ + // 图表主标题 + // title: { + // text: '世界地图', // 主标题文本,支持使用 \n 换行 + // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比 + // left: 'center', // 值: 'left', 'center', 'right' 同上 + // textStyle: { // 文本样式 + // fontSize: 24, + // fontWeight: 600, + // color: '#000' + // } + // }, + + grid: { + width: '100%', + height: '100%', + left: '0%', + right: '0%', + bottom: '0%', + containLabel: true + }, + // 提示框组件 + tooltip: { + trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用 + // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式 + // 使用函数模板 传入的数据值 -> value: number | Array + formatter: function(val) { + if (val.data == null) return + return val.data.name + ': ' + val.data.value + } + }, + // 视觉映射组件 + visualMap: { + min: 0, + max: 10000, + text: ['max', 'min'], + realtime: false, + calculable: true, + color: ['#4608AD', '#d9e4ff'] + }, + series: [ + { + type: 'map', // 类型 + // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列 + name: '世界地图', + mapType: 'world', // 地图类型 + // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启 + roam: true, + // 图形上的文本标签 + label: { + show: false // 是否显示对应地名 + }, + zoom: 1.2, + // 地图区域的多边形 图形样式 + itemStyle: { + // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用 + borderWidth: 0.5, // 描边线宽 为 0 时无描边 + borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数 + borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted' + }, + // 高亮状态下的多边形和标签样式 + emphasis: { + label: { + show: true, // 是否显示标签 + color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色 + }, + itemStyle: { + areaColor: '#FF6347' // 地图区域的颜色 + } + }, + // 自定义地区的名称映射 + nameMap: name, + // 地图系列中的数据内容数组 数组项可以为单个数值 + data: data + } + ] + }) + } + } +} +</script> +<style lang="scss"> +.wrapper { + width: 100%; +} +.wrapper .chart1{ + width: 60%; + /* margin:0 auto; */ + height: 400px; + /* border: 1px solid #eeeeee; */ + /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/ + background-size: 100% 100%; + background-color: #fff; +} +.chart1 { + width: 100%; + height: 100%; + background-color: yellow; + +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Openrdns.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Openrdns.vue new file mode 100644 index 0000000..20a42cf --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53Openrdns.vue @@ -0,0 +1,166 @@ +<template> + <div class="wrapper"> + <div id="chart5" class="chart" /> + </div> +</template> + +<script> +import echarts from 'echarts' +export default { + props: ['do53opendns'], + data() { + return {} + }, + mounted() { + this.getWorld(this.do53opendns) + var myChartContainer = document.getElementById('chart5') + // 获取自适应的高度和宽度 + var resizeMyChartContainer = function() { + // myChartContainer.style.height = window.innerHeight * 0.65 + 'px'; + // myChartContainer.style.width = window.innerWidth * 0.75 + 'px'; + myChartContainer.style.height = 300 + 'px' + myChartContainer.style.width = 600 + 'px' + if (window.innerWidth > 768 && window.innerWidth < 1370) { + myChartContainer.style.width = 500 + 'px' + } + } + // 设置容器高和宽 + resizeMyChartContainer() + var myChart = echarts.init(myChartContainer) + const option = {} + myChart.setOption(option) + }, + methods: { + changeKey(arr, key) { + const newArr = [] + arr.forEach((item, index) => { + const newObj = {} + for (var i = 0; i < key.length; i++) { + newObj[key[i]] = item[Object.keys(item)[i]] + } + newArr.push(newObj) + }) + return newArr + }, + getWorld(data) { + const list = this.changeKey(this.do53opendns, ['name', 'value']) + var that = this + // const {ctx} = getCurrentInstance() + this.$axios.get('/sjData/word.json').then(function(res) { + // console.log(list,111); + const namemap = res.data.namemap + const dataArr = list + // let dataArr = data.data + that.drawChart(namemap, dataArr) + }) + }, + drawChart(name, data) { + // 基于准备好的dom,初始化echarts实例 + const chart = echarts.init(document.getElementById('chart5')) + + // 监听屏幕变化自动缩放图表 + window.addEventListener('resize', function() { + chart.resize() + }) + // 绘制图表 + chart.setOption({ + // 图表主标题 + // title: { + // text: '世界地图', // 主标题文本,支持使用 \n 换行 + // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比 + // left: 'center', // 值: 'left', 'center', 'right' 同上 + // textStyle: { // 文本样式 + // fontSize: 24, + // fontWeight: 600, + // color: '#000' + // } + // }, + + grid: { + width: '100%', + height: '100%', + left: '0%', + right: '0%', + bottom: '0%', + containLabel: true + }, + // 提示框组件 + tooltip: { + trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用 + // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式 + // 使用函数模板 传入的数据值 -> value: number | Array + formatter: function(val) { + if (val.data == null) return + return val.data.name + ': ' + val.data.value + } + }, + // 视觉映射组件 + visualMap: { + min: 0, + max: 10000, + text: ['max', 'min'], + realtime: false, + calculable: true, + color: ['#4608AD', '#d9e4ff'] + }, + series: [ + { + type: 'map', // 类型 + // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列 + name: '世界地图', + mapType: 'world', // 地图类型 + // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启 + roam: true, + // 图形上的文本标签 + label: { + show: false // 是否显示对应地名 + }, + zoom: 1.2, + // 地图区域的多边形 图形样式 + itemStyle: { + // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用 + borderWidth: 0.5, // 描边线宽 为 0 时无描边 + borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数 + borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted' + }, + // 高亮状态下的多边形和标签样式 + emphasis: { + label: { + show: true, // 是否显示标签 + color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色 + }, + itemStyle: { + areaColor: '#FF6347' // 地图区域的颜色 + } + }, + // 自定义地区的名称映射 + nameMap: name, + // 地图系列中的数据内容数组 数组项可以为单个数值 + data: data + } + ] + }) + } + } +} +</script> +<style lang="scss"> +.wrapper { + width: 100%; +} +.wrapper .chart1{ + width: 60%; + /* margin:0 auto; */ + height: 400px; + /* border: 1px solid #eeeeee; */ + /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/ + background-size: 100% 100%; + background-color: #fff; +} +.chart1 { + width: 100%; + height: 100%; + background-color: yellow; + +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53sj.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53sj.vue new file mode 100644 index 0000000..06ff958 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53sj.vue @@ -0,0 +1,166 @@ +<template> + <div class="wrapper"> + <div id="chart1" class="chart" /> + </div> +</template> + +<script> +import echarts from 'echarts' +export default { + props: ['do53sj'], + data() { + return {} + }, + mounted() { + this.getWorld(this.do53sj) + var myChartContainer = document.getElementById('chart1') + // 获取自适应的高度和宽度 + var resizeMyChartContainer = function() { + // myChartContainer.style.height = window.innerHeight * 0.65 + 'px'; + // myChartContainer.style.width = window.innerWidth * 0.75 + 'px'; + myChartContainer.style.height = 300 + 'px' + myChartContainer.style.width = 600 + 'px' + if (window.innerWidth > 768 && window.innerWidth < 1370) { + myChartContainer.style.width = 500 + 'px' + } + } + // 设置容器高和宽 + resizeMyChartContainer() + var myChart = echarts.init(myChartContainer) + const option = {} + myChart.setOption(option) + }, + methods: { + changeKey(arr, key) { + const newArr = [] + arr.forEach((item, index) => { + const newObj = {} + for (var i = 0; i < key.length; i++) { + newObj[key[i]] = item[Object.keys(item)[i]] + } + newArr.push(newObj) + }) + return newArr + }, + getWorld(data) { + const list = this.changeKey(this.do53sj, ['name', 'value']) + var that = this + // const {ctx} = getCurrentInstance() + this.$axios.get('/sjData/word.json').then(function(res) { + // console.log(res); + const namemap = res.data.namemap + const dataArr = list + // let dataArr = data.data + that.drawChart(namemap, dataArr) + }) + }, + drawChart(name, data) { + // 基于准备好的dom,初始化echarts实例 + const chart = echarts.init(document.getElementById('chart1')) + + // 监听屏幕变化自动缩放图表 + window.addEventListener('resize', function() { + chart.resize() + }) + // 绘制图表 + chart.setOption({ + // 图表主标题 + // title: { + // text: '世界地图', // 主标题文本,支持使用 \n 换行 + // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比 + // left: 'center', // 值: 'left', 'center', 'right' 同上 + // textStyle: { // 文本样式 + // fontSize: 24, + // fontWeight: 600, + // color: '#000' + // } + // }, + + grid: { + width: '100%', + height: '100%', + left: '0%', + right: '0%', + bottom: '0%', + containLabel: true + }, + // 提示框组件 + tooltip: { + trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用 + // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式 + // 使用函数模板 传入的数据值 -> value: number | Array + formatter: function(val) { + if (val.data == null) return + return val.data.name + ': ' + val.data.value + } + }, + // 视觉映射组件 + visualMap: { + min: 0, + max: 10000, + text: ['max', 'min'], + realtime: false, + calculable: true, + color: ['#4608AD', '#d9e4ff'] + }, + series: [ + { + type: 'map', // 类型 + // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列 + name: '世界地图', + mapType: 'world', // 地图类型 + // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启 + roam: true, + // 图形上的文本标签 + label: { + show: false // 是否显示对应地名 + }, + zoom: 1.2, + // 地图区域的多边形 图形样式 + itemStyle: { + // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用 + borderWidth: 0.5, // 描边线宽 为 0 时无描边 + borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数 + borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted' + }, + // 高亮状态下的多边形和标签样式 + emphasis: { + label: { + show: true, // 是否显示标签 + color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色 + }, + itemStyle: { + areaColor: '#FF6347' // 地图区域的颜色 + } + }, + // 自定义地区的名称映射 + nameMap: name, + // 地图系列中的数据内容数组 数组项可以为单个数值 + data: data + } + ] + }) + } + } +} +</script> +<style lang="scss"> +.wrapper { + width: 100%; +} +.wrapper .chart1{ + width: 60%; + /* margin:0 auto; */ + height: 400px; + /* border: 1px solid #eeeeee; */ + /* background: url(../../public/static/bg.png) no-repeat; 背景图设置*/ + background-size: 100% 100%; + background-color: #fff; +} +.chart1 { + width: 100%; + height: 100%; + background-color: yellow; + +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53zg.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53zg.vue new file mode 100644 index 0000000..3ab40d6 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Do53zg.vue @@ -0,0 +1,145 @@ +<template> + <div id="map1" ref="do53zg" :style="{ width: '100%', height: '100%' }" /> +</template> +<script> +import chinaGeoCoordMap from '../../utils/chinamap' +import echarts from 'echarts' +export default { + name: 'Map1', + props: ['do53zg'], + data() { + return {} + }, + mounted() { + // console.log(this.dohzg,234); + var myChartContainer = document.getElementById('map1') + // 获取自适应的高度和宽度 + var resizeMyChartContainer = function() { + myChartContainer.style.height = 300 + 'px' + myChartContainer.style.width = 600 + 'px' + if (window.innerWidth > 768 && window.innerWidth < 1370) { + myChartContainer.style.width = 500 + 'px' + } + } + // 设置容器高和宽 + resizeMyChartContainer() + var map = echarts.init(myChartContainer) + const option = {} + map.setOption(option) + const dohzglist = this.changeKey(this.do53zg, ['name', 'value']) + // console.log(dohzglist,234); + this.initditu(dohzglist, chinaGeoCoordMap.chinaGeoCoordMap) + }, + methods: { + changeKey(arr, key) { + const newArr = [] + arr.forEach((item, index) => { + const newObj = {} + for (var i = 0; i < key.length; i++) { + newObj[key[i]] = item[Object.keys(item)[i]] + } + newArr.push(newObj) + }) + return newArr + }, + + initditu(dataCount) { + // console.log(dataCount,1111); + var datasa = dataCount + // var chinaDatas = this.transmitData; + // 基于准备好的dom,初始化echarts实例 + const map = this.$echarts.init(document.getElementById('map1')) + // var chinaDatas = transmitData; + + var series = [] + var color = ['#57df1c']; + [['', this.chinaDatas]].forEach(function(item, i) { + // console.log(item, 123); + series.push( + { + type: 'lines' + }, + { + type: 'effectScatter', + coordinateSystem: 'geo' + }, + // 被攻击点 + { + type: 'effectScatter', + coordinateSystem: 'geo', + zlevel: 2 + }, + { + type: 'map', + map: 'china', + geoIndex: 0, + aspectScale: 0.75, // 长宽比 + showLegendSymbol: false, // 存在legend时显示 + label: { + normal: { + show: true + }, + emphasis: { + show: false, + textStyle: { + color: '#fff' + } + } + }, + roam: true, + animation: false, + data: datasa + } + ) + }) + + map.setOption({ + tooltip: { + trigger: 'item', + formatter: function(val) { + if (val.data == null) return + return val.data.name + ': ' + val.data.value + } + }, + visualMap: { + show: true, + min: 0, + max: 200, + left: 'left', + top: 'bottom', + text: ['max', 'min'], // 文本,默认为数值文本 + calculable: true, + seriesIndex: [3], + inRange: { + color: ['#d9e4ff', '#4608AD'] + } + }, + geo: { + map: 'china', + roam: true, // 是否允许缩放 + zoom: 1.14, + label: { + emphasis: { + show: true + } + }, + itemStyle: { + normal: { + show: false, + color: 'rgba(48,97,186,0)', // 地图背景色 + borderColor: '#000' // 省市边界线 + }, + emphasis: { + show: false, + color: '#ff6347' // 悬浮背景 + } + } + }, + series: series + }) + } + } +} +</script> +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohsj.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohsj.vue new file mode 100644 index 0000000..03510a5 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohsj.vue @@ -0,0 +1,163 @@ +<template> + <div id="wrapper" class="wrapper"> + <div id="chart" class="chart" /> + </div> +</template> + +<script> +import echarts from 'echarts' +export default { + props: ['dohsj'], + data() { + return {} + }, + mounted() { + this.getWorld(this.dohsj) + var myChartContainer = document.getElementById('chart') + var resizeMyChartContainer = function() { + myChartContainer.style.height = 300 + 'px' + myChartContainer.style.width = 600 + 'px' + // console.log(window.innerWidth) + if (window.innerWidth > 768 && window.innerWidth < 1370) { + myChartContainer.style.width = 500 + 'px' + } + } + // 设置容器高和宽 + resizeMyChartContainer() + var map = echarts.init(myChartContainer) + const option = {} + map.setOption(option) + }, + methods: { + changeKey(arr, key) { + const newArr = [] + arr.forEach((item, index) => { + const newObj = {} + for (var i = 0; i < key.length; i++) { + newObj[key[i]] = item[Object.keys(item)[i]] + } + newArr.push(newObj) + }) + return newArr + }, + + getWorld(data) { + const list = this.changeKey(this.dohsj, ['name', 'value']) + // console.log(list,456); + var that = this + this.$axios.get('/sjData/word.json').then(function(res) { + // console.log(list,333); + const namemap = res.data.namemap + const dataArr = list + // console.log(dataArr,6666); + // let dataArr = data.data + that.drawChart(namemap, dataArr) + }) + }, + + drawChart(name, data) { + // 基于准备好的dom,初始化echarts实例 + const chart = echarts.init(document.getElementById('chart')) + + // 监听屏幕变化自动缩放图表 + window.addEventListener('resize', function() { + chart.resize() + }) + // 绘制图表 + chart.setOption({ + // 图表主标题 + // title: { + // text: '世界地图', // 主标题文本,支持使用 \n 换行 + // top: 10, // 定位 值: 'top', 'middle', 'bottom' 也可以是具体的值或者百分比 + // left: 'center', // 值: 'left', 'center', 'right' 同上 + // textStyle: { // 文本样式 + // fontSize: 24, + // fontWeight: 600, + // color: '#000' + // } + // }, + grid: { + width: '100%', + height: '100%', + left: '0%', + right: '0%', + bottom: '0%', + containLabel: true + }, + // 提示框组件 + tooltip: { + trigger: 'item', // 触发类型, 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用 + // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式 + // 使用函数模板 传入的数据值 -> value: number | Array + formatter: function(val) { + if (val.data == null) return + return val.data.name + ': ' + val.data.value + } + }, + // 视觉映射组件 + visualMap: { + min: 0, + max: 100000, + text: ['max', 'min'], + realtime: false, + calculable: true, + color: ['#4608AD', '#d9e4ff'] + }, + series: [ + { + type: 'map', // 类型 + // 系列名称,用于tooltip的显示,legend 的图例筛选 在 setOption 更新数据和配置项时用于指定对应的系列 + name: '世界地图', + mapType: 'world', // 地图类型 + // 是否开启鼠标缩放和平移漫游 默认不开启 如果只想要开启缩放或者平移,可以设置成 'scale' 或者 'move' 设置成 true 为都开启 + roam: true, + // 图形上的文本标签 + label: { + show: false // 是否显示对应地名 + }, + zoom: 1.2, + // 地图区域的多边形 图形样式 + itemStyle: { + // areaColor: '#7B68EE', // 地图区域的颜色 如果设置了visualMap,areaColor属性将不起作用 + borderWidth: 0.5, // 描边线宽 为 0 时无描边 + borderColor: '#000', // 图形的描边颜色 支持的颜色格式同 color,不支持回调函数 + borderType: 'solid' // 描边类型,默认为实线,支持 'solid', 'dashed', 'dotted' + }, + // 高亮状态下的多边形和标签样式 + emphasis: { + label: { + show: true, // 是否显示标签 + color: '#fff' // 文字的颜色 如果设置为 'auto',则为视觉映射得到的颜色,如系列色 + }, + itemStyle: { + areaColor: '#FF6347' // 地图区域的颜色 + } + }, + // 自定义地区的名称映射 + nameMap: name, + // 地图系列中的数据内容数组 数组项可以为单个数值 + data: data + } + ] + }) + } + } +} +</script> +<style lang="scss"> +.wrapper { + width: 100%; + height: 100%; +} +.wrapper .chart { + width: 100%; + background-size: 100% 100%; + background-color: #fff; +} +.chart { + width: 100%; + height: 100%; + // background-color: yellow; + +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohzg.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohzg.vue new file mode 100644 index 0000000..812b58e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Dohzg.vue @@ -0,0 +1,145 @@ +<template> + <div id="map" ref="dohzg" :style="{ width: '100%', height: '100%' }" /> +</template> +<script> +import chinaGeoCoordMap from '../../utils/chinamap' +import echarts from 'echarts' +export default { + name: 'Map', + props: ['dohzg'], + data() { + return {} + }, + mounted() { + // console.log(this.dohzg,234); + var myChartContainer = document.getElementById('map') + // 获取自适应的高度和宽度 + var resizeMyChartContainer = function() { + myChartContainer.style.height = 300 + 'px' + myChartContainer.style.width = 600 + 'px' + if (window.innerWidth > 768 && window.innerWidth < 1370) { + myChartContainer.style.width = 500 + 'px' + } + } + // 设置容器高和宽 + resizeMyChartContainer() + var map = echarts.init(myChartContainer) + const option = {} + map.setOption(option) + const dohzglist = this.changeKey(this.dohzg, ['name', 'value']) + // console.log(dohzglist,234); + this.initditu(dohzglist, chinaGeoCoordMap.chinaGeoCoordMap) + }, + methods: { + changeKey(arr, key) { + const newArr = [] + arr.forEach((item, index) => { + const newObj = {} + for (var i = 0; i < key.length; i++) { + newObj[key[i]] = item[Object.keys(item)[i]] + } + newArr.push(newObj) + }) + return newArr + }, + + initditu(dataCount, chinaGeoCoordMap) { + // console.log(dataCount,1111); + var datasa = dataCount + // var chinaDatas = this.transmitData; + // 基于准备好的dom,初始化echarts实例 + const map = this.$echarts.init(document.getElementById('map')) + // var chinaDatas = transmitData; + + var series = [] + var color = ['#57df1c']; + [['', this.chinaDatas]].forEach(function(item, i) { + // console.log(item, 123); + series.push( + { + type: 'lines' + }, + { + type: 'effectScatter', + coordinateSystem: 'geo' + }, + // 被攻击点 + { + type: 'effectScatter', + coordinateSystem: 'geo', + zlevel: 2 + }, + { + type: 'map', + map: 'china', + geoIndex: 0, + aspectScale: 0.75, // 长宽比 + showLegendSymbol: false, // 存在legend时显示 + label: { + normal: { + show: true + }, + emphasis: { + show: false, + textStyle: { + color: '#fff' + } + } + }, + roam: true, + animation: false, + data: datasa + } + ) + }) + + map.setOption({ + tooltip: { + trigger: 'item', + formatter: function(val) { + if (val.data == null) return + return val.data.name + ': ' + val.data.value + } + }, + visualMap: { + show: true, + min: 0, + max: 200, + left: 'left', + top: 'bottom', + text: ['max', 'min'], // 文本,默认为数值文本 + calculable: true, + seriesIndex: [3], + inRange: { + color: ['#d9e4ff', '#4608AD'] + } + }, + geo: { + map: 'china', + roam: true, // 是否允许缩放 + zoom: 1.14, + label: { + emphasis: { + show: true + } + }, + itemStyle: { + normal: { + show: false, + color: 'rgba(48,97,186,0)', // 地图背景色 + borderColor: '#000' // 省市边界线 + }, + emphasis: { + show: false, + color: '#ff6347' // 悬浮背景 + } + } + }, + series: series + }) + } + } +} +</script> +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Funnel.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Funnel.vue new file mode 100644 index 0000000..380b373 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Funnel.vue @@ -0,0 +1,120 @@ +<template> + <div :class="className" :style="{height:height,width:width}" /> +</template> + +<script> +import echarts from 'echarts' + +require('echarts/theme/macarons') // echarts theme +import { debounce } from '@/utils' + +export default { + props: { + className: { + type: String, + default: 'chart' + }, + width: { + type: String, + default: '100%' + }, + height: { + type: String, + default: '300px' + } + }, + data() { + return { + chart: null + } + }, + mounted() { + this.initChart() + this.__resizeHandler = debounce(() => { + if (this.chart) { + this.chart.resize() + } + }, 100) + window.addEventListener('resize', this.__resizeHandler) + }, + beforeDestroy() { + if (!this.chart) { + return + } + window.removeEventListener('resize', this.__resizeHandler) + this.chart.dispose() + this.chart = null + }, + methods: { + initChart() { + this.chart = echarts.init(this.$el, 'macarons') + + this.chart.setOption({ + title: { + text: '漏斗图', + subtext: '纯属虚构' + }, + tooltip: { + trigger: 'item', + formatter: '{a} <br/>{b} : {c}%' + }, + toolbox: { + feature: { + dataView: { readOnly: false }, + restore: {}, + saveAsImage: {} + } + }, + legend: { + data: ['展现', '点击', '访问', '咨询', '订单'] + }, + calculable: true, + series: [ + { + name: '漏斗图', + type: 'funnel', + left: '10%', + top: 60, + bottom: 60, + width: '80%', + // height: {totalHeight} - y - y2, + min: 0, + max: 100, + minSize: '0%', + maxSize: '100%', + sort: 'descending', + gap: 2, + label: { + show: true, + position: 'inside' + }, + labelLine: { + length: 10, + lineStyle: { + width: 1, + type: 'solid' + } + }, + itemStyle: { + borderColor: '#fff', + borderWidth: 1 + }, + emphasis: { + label: { + fontSize: 20 + } + }, + data: [ + { value: 60, name: '访问' }, + { value: 40, name: '咨询' }, + { value: 20, name: '订单' }, + { value: 80, name: '点击' }, + { value: 100, name: '展现' } + ] + } + ] + }) + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/PieChart.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/PieChart.vue new file mode 100644 index 0000000..ff1bc52 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/PieChart.vue @@ -0,0 +1,84 @@ +<template> + <div :class="className" :style="{height:height,width:width}" /> +</template> + +<script> +import echarts from 'echarts' +require('echarts/theme/macarons') // echarts theme +import { debounce } from '@/utils' + +export default { + props: { + className: { + type: String, + default: 'chart' + }, + width: { + type: String, + default: '100%' + }, + height: { + type: String, + default: '300px' + } + }, + data() { + return { + chart: null + } + }, + mounted() { + this.initChart() + this.__resizeHandler = debounce(() => { + if (this.chart) { + this.chart.resize() + } + }, 100) + window.addEventListener('resize', this.__resizeHandler) + }, + beforeDestroy() { + if (!this.chart) { + return + } + window.removeEventListener('resize', this.__resizeHandler) + this.chart.dispose() + this.chart = null + }, + methods: { + initChart() { + this.chart = echarts.init(this.$el, 'macarons') + + this.chart.setOption({ + tooltip: { + trigger: 'item', + formatter: '{a} <br/>{b} : {c} ({d}%)' + }, + legend: { + left: 'center', + bottom: '10', + data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts'] + }, + calculable: true, + series: [ + { + name: 'WEEKLY WRITE ARTICLES', + type: 'pie', + roseType: 'radius', + radius: [15, 95], + center: ['50%', '38%'], + data: [ + { value: 320, name: 'Industries' }, + { value: 240, name: 'Technology' }, + { value: 149, name: 'Forex' }, + { value: 100, name: 'Gold' }, + { value: 59, name: 'Forecasts' } + ], + animationEasing: 'cubicInOut', + animationDuration: 2600 + } + ] + }) + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/Echarts/Time.vue b/UI source code/dns_mapping_ui-master/src/components/Echarts/Time.vue new file mode 100644 index 0000000..4ab9c55 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Echarts/Time.vue @@ -0,0 +1,104 @@ +<template> + <!-- <div id="Time" class="Time" :style="{height:height,width:width}" /> --> + <div class="wrapper"> + <div id="Time" class="chart" /> + </div> +</template> + +<script> +import echarts from 'echarts' +export default { + + data() { + return { + + } + }, + mounted() { + // this.initChart() + var myChartContainer = document.getElementById('Time') + + // 获取自适应的高度和宽度 + var resizeMyChartContainer = function() { + // myChartContainer.style.height = window.innerHeight * 0.65 + 'px'; + // myChartContainer.style.width = window.innerWidth * 0.75 + 'px'; + myChartContainer.style.height = 100 + 'px' + myChartContainer.style.width = 1182+'px' + if (window.innerWidth > 768 && window.innerWidth < 1370) { + myChartContainer.style.width = 945 + 'px' + } + } + // 设置容器高和宽 + resizeMyChartContainer() + var myChart = echarts.init(myChartContainer) + const option = {} + myChart.setOption(option) + this.initChart() + }, + methods: { + initChart() { + // this.chart = echarts.init(this.$el, 'macarons') + const chart = echarts.init(document.getElementById('Time')) + // 监听屏幕变化自动缩放图表 + window.addEventListener('resize', function() { + chart.resize() + }) + + + + chart.setOption({ + baseOption: { + timeline: { + axisType: 'category', + autoPlay: true, + playInterval: 1000, + data: [ + '2002-01-01', '2003-01-01', '2004-01-01', + { + value: '2005-01-01', + tooltip: { + formatter: '{b} GDP达到一个高度' + }, + symbol: 'diamond', + symbolSize: 16 + }, + '2006-01-01', '2007-01-01', '2008-01-01', '2009-01-01', '2010-01-01', + { + value: '2011-01-01', + tooltip: { + formatter: function(params) { + return params.name + 'GDP达到又一个高度' + } + }, + symbol: 'diamond', + symbolSize: 18 + } + ], + label: { + formatter: function(s) { + return (new Date(s)).getFullYear() + } + } + }, + + calculable: true, + + + series: [ + + ] + }, + options: [ + + + ] + }) + } + } +} +</script> +<style scoped> +.wrapper { + width: 100%; +} +</style>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/FilteredSearch.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/FilteredSearch.vue new file mode 100644 index 0000000..afe1155 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/FilteredSearch.vue @@ -0,0 +1,518 @@ +<template> + <div class="filtered-search-container" v-clickoutside="handleClickoutside" v-idscope id="filtersearch"> + <!-- 搜索框容器 --> + <div class="filtered-search-box" :class="isFocus ? 'focus':''"> + <!-- 历史记录下拉菜单...` --> + <!-- <recent-search ref="historySearch" @selectHistory="setDefaultItems"/> --> + <!-- <el-divider direction="vertical" class="divider"></el-divider> --> + <div class="scroll-container"> + <div class="list-container"> + <search-item + :key="item.id" + v-for="(item,index) in selectItems" + :id="item.label" + @del="handleDel" + @active="handleActive" + @moveTo="handleMove" + @clickItem="handleClickItem" + :currentIndex="index" + :isLast="index === selectItems.length-1" + :selectItem="item" :ref="'selectItem'+index"/> + <el-select + id="select-label" + ref="select" + :popper-append-to-body="true" + popper-class="select-popper select-list-zindex" + class="label-select" + v-if="conditionConfig.isShow" + v-model="conditionConfig.currentCondition" + @change="addCondition" + @focus="handleFocus" + @blur="handleBlur" + size="mini" + remote + filterable + :allow-create="false" + default-first-option + @keydown.native="handleKeydown" + @visible-change="visibleChangeHandle" + placeholder="请输入检索内容"> + <template v-for="item in conditionConfig.conditionList"> + <el-option + :id="item.id" + v-idscope + :disabled="item.disabled === true" + :key="item.id" + v-if="item.visible!==false" + :label="item.name" + :value="item.id"> + </el-option> + </template> + </el-select> + </div> + </div> + <i id="searchClear" v-if="selectItems && selectItems.length>0" class="el-icon-close clear-icon" + @click="handleClear"></i> + </div> + <i id="searchQuery" class="el-icon-search search-icon" @click="handleQuery"></i> + </div> +</template> + +<script> + /* + * { + id: 1, + name: 'ID', + icon: 'iconfont icon-id', + type: 'input', + label: 'profileId', + disabled: false, + visiable:true, + value:'' + }, + * */ + // import fireKeyEvent from './components/keyboard' + import searchHistory from './components/historyApi' + import SearchItem from './components/SearchItem.vue' + import lodashCloneDeep from 'lodash/cloneDeep' + import getTxt1CursorPosition from './components/cursorPosition' + import {cloneDeep, debounce} from "lodash"; + + + export default { + name: "FilteredSearch", + components: { + // GlIcon, + RecentSearch: () => import('./components/RecentSearch.vue'), + SearchItem + }, + props: { //参数 ... + historyKey: {}, + sourceList: {}, //原始 查询条件列表 + defaultList: {} //默认选中值 --可选 + }, + data() { + return { + //标签列表 可选的参数分类 + conditionConfig: { + conditionList: [], + isShow: true, + currentCondition: "", //当前搜索条件 + currentIndex: 0 //当前 指针位置 + }, + //选中的数据 ... + selectItems: [], + //对外输入框 搜索过滤框 + isFocus: false, + permission: JSON.parse(localStorage.getItem('permissions')) + }; + }, + created() { + this.setDefaultItems() + }, + methods: { + sortConditoins() { + //列表排序 ... + // conditionConfig.conditionList + + }, + // handleClickItem() { + // // 下拉 和 历史数据悬浮同时存在 问题(预留) + // // this.$refs.historySearch ? this.$refs.historySearch.visible=false :'' + // }, + // handleClickoutside() { + + // }, + handleMove({toIndex, self}) { + if (toIndex < 0 || toIndex > this.selectItems.length - 1) { + self.handleBlur() + return + } + this.focusItem(toIndex) + }, + handleActive({currentIndex, currentItem}) { + if (currentIndex === this.conditionConfig.currentIndex) { + return + } + // this.conditionConfig.currentCondition=currentItem.id + this.conditionConfig.currentIndex = currentIndex + }, + validator(resultMap) { + var validField = ['id', 'profileId'] + var errList = [] + var reg = /^[\d,]*$/; + validField.forEach((field) => { + var val = resultMap[field] || ''; + if (field === 'id' || field === 'profileId') { + var idList = val.split(',') + idList.forEach((item) => { + if (item && !reg.test(item)) { + errList.push(this.$t('i18n.overall.searchInfo.idValid')) + } else { + if (item && (+item >= 2147483647)) { + errList.push(this.$t("maxnumTips")) + } + } + }) + } + }); + return errList + }, + handleQuery: debounce(function () { + //执行查询方法 对外抛出查询参数... + console.log("执行查询方法"); + searchHistory.addItem(this.selectItems, this.historyKey); + var resultMap = {} + this.selectItems.forEach((item, index) => { + resultMap[item.label] = item.value + }); + //校验查询条件 + var errList = [] + console.log(resultMap); + errList = this.validator(resultMap) || [] + if (errList.length > 0) { + this.$message.error(errList[0]); + return + } + + this.$emit('query', resultMap, this.selectItems); + //重新刷新一下 下拉(防止用户反复回车-可以删除) + this.conditionConfig.isShow = false + setTimeout(() => { + this.isFocus = false + this.conditionConfig.isShow = true + }) + }, 500), + handleKeydown(e) { + var keyCode = window.event ? e.keyCode : e.which; + //删除事件 + this.$nextTick(() => { + var dom = this.$refs.select ? $(this.$refs.select.$el).find('input')[0] : ''; + var cursorIndex = dom ? getTxt1CursorPosition(dom, document) || 0 : 0; + + //回车 直接回车搜索(备用) + if (keyCode === 13) { + if (this.$refs.select && this.$refs.select.hoverIndex === -1) { + this.$refs.select.visible = false; + if (this.isFocus) { + this.handleQuery() + } + this.isFocus = false + } + } + if (keyCode === 8) { + if (this.$refs.select.query === "" || this.$refs.select.query == null) { + var focusIndex = this.conditionConfig.currentIndex - 1; + setTimeout(() => { + this.focusItem(focusIndex) + }) + } + } + if (keyCode === 37) { //左箭头 || 38 右箭头 + if (cursorIndex === 0) { + // console.log('左箭头到头了'); + var leftIndex = this.conditionConfig.currentIndex - 1; + setTimeout(() => { + this.focusItem(leftIndex) + }) + } + } + if (keyCode === 39) { //左箭头 || 38 右箭头 + if (!this.$refs.select.query || cursorIndex === this.$refs.select.query.length) { + // console.log('右箭头到头了'); + } + } + }); + }, + setDefaultItems(historyList = []) { + // this.handleClear(); + var permanentItems = [{ + id: -1, + name: this.$t("i18n.overall.searchList.defaultName"), + }]; + for(let v of this.sourceList){ + if(v.id === 6||v.id === 666){ + if(!this.permission['system_accounts/system_UserManagement']){ + v.visible=false + } + } + } + this.conditionConfig.conditionList = permanentItems.concat(this.sourceList); + //存在 历史记录 就走历史记录, 否则就选中 默认选中值... + var selectList = []; + var conditionList = []; + + if (historyList && historyList.length > 0) { + selectList = historyList; + } else { + selectList = this.defaultList; + } + + conditionList = lodashCloneDeep(this.conditionConfig.conditionList) || []; + //获取已存在 字段id + conditionList = conditionList.filter((item, index) => { + var findIndex = null; + var findItem = selectList.find((selItem, selIndex) => { + if (selItem.id === item.id) { + findIndex = selIndex; + return true //考虑对象合并 + } + return false + }); + + if (findItem) { + return false + } + return true + }); + this.conditionConfig.conditionList = conditionList; + this.selectItems = selectList + //点击历史记录输入框聚焦 + if (historyList && historyList.length > 0) { + this.$nextTick((x) => { + this.$refs.select.focus() + }) + } + }, + visibleChangeHandle(state) { + if (state) { + this.isFocus = true + this.handleClickItem() + } + }, + triggerFocus() { + this.$nextTick(() => { + if (this.conditionConfig.isShow === true) { + if (this.conditionConfig.conditionList.length <= 0) { + return + } + var dom = this.$refs.select.$el.children[0]; //获取输入框DOM 索引 + dom.click(); + } + }) + // setTimeout(() => { + // if (this.conditionConfig.isShow === true) { + // if (this.conditionConfig.conditionList.length <= 0) { + // return + // } + // var dom = this.$refs.select.$el.children[0]; //获取输入框DOM 索引 + // dom.click(); + // } + // }, 200) + }, + handleFocus() { + this.isFocus = true + }, + handleBlur() { + this.isFocus = false + }, + focusItem(index) { + //选中某一项 + if (this.selectItems && this.selectItems.length > 0) { + this.$nextTick(() => { + var lastComponent = this.$refs['selectItem' + index] && this.$refs['selectItem' + index][0]; + lastComponent && lastComponent.handleFocus && lastComponent.handleFocus() + }); + } + }, + addCondition(conditionCode) { + if (conditionCode === -1) { + this.handleQuery(); + this.conditionConfig.currentCondition = null; + this.$refs.select.visible = false; + return + } + var currentIndex = null; + var addItem = this.conditionConfig.conditionList.find((item, index) => { + if (item.id === conditionCode) { + currentIndex = index; + return true + } + return false + }); + //增加一项选中数据 且 删除标签该项 + if (addItem) { + addItem.value = addItem.defaultVal; + this.selectItems.push(addItem); + this.conditionConfig.conditionList.splice(currentIndex, 1) + } + //最后一个搜索项 聚焦 + // if (this.selectItems && this.selectItems.length > 0) { + // this.$nextTick(() => { + // var lastIndex = this.selectItems.length - 1; + // var lastComponent = this.$refs['selectItem' + lastIndex] && this.$refs['selectItem' + lastIndex][0]; + // lastComponent && lastComponent.handleFocus && lastComponent.handleFocus() + // }); + // } + var lastIndex = this.selectItems.length - 1; + this.focusItem(lastIndex) + this.conditionConfig.currentCondition = null + this.conditionConfig.isShow = false + }, + handleReset() { + this.selectItems = [] + this.conditionConfig.currentCondition = "" + this.conditionConfig.currentIndex = 0 + }, + handleClear() { + this.selectItems.forEach((item, index) => { + item.value = '' + this.conditionConfig.conditionList.push(item) + }); + this.selectItems = []; + + this.conditionConfig.isShow = true + }, + handleDel(delItem) { + var delIndex = this.selectItems.findIndex((item, index) => { + if (delItem.id === item.id) { + delIndex = index; + return true + } + return false + }); + this.selectItems.splice(delIndex, 1); + delItem.value = delItem.defaultVal; + this.conditionConfig.conditionList.push(delItem); + } + }, + watch: { + isFocus(n, o) { + this.$emit("focus", n) + }, + 'conditionConfig.isShow': { + handler(n, o) { + if (n) { + //如果是 展示了那么 + this.conditionConfig.currentIndex = this.selectItems.length + } + }, + deep: false, + immediate: true + }, + sourceList: { + handler(n, o) { + this.setDefaultItems() + // this.conditionConfig.conditionList = n; + }, + deep: false, + immediate: false + }, + selectItems: { + handler: debounce(function (n, o) { + //当选中数据变化的时候 ,去修改标签可选择列表项 + this.$emit('change', { + selectItems: this.selectItems, + conditionList: this.conditionConfig.conditionList + }) + }, 100), + deep: true, + immediate: false + } + } + }; +</script> +<style lang="less" scoped> + .filtered-search-container { + /*padding: 0 10px;*/ + display: flex; + + .filtered-search-box { + flex: 1; + } + + /deep/ .label-select input.el-input__inner { + width: 100%; + padding-right: 10px; + } + } + + /* 聚焦样式 */ + .filtered-search-box.focus { + border-color: #73afea; + box-shadow: 0 0 4px rgba(115, 175, 234, 0.4); + } + + .filtered-search-box { + position: relative; + display: flex; + width: 100%; + min-width: 0; + border: 1px solid #e5e5e5; + background-color: #fff; + border-radius: 4px 0 0 4px; + /*padding: 2px 0;*/ + } + + .divider { + height: auto !important; + margin: 0 !important; + } + + .list-container { + list-style: none; + display: flex; + position: relative; + margin-bottom: 0; + width: auto; + padding-left: 8px; + box-sizing: border-box; + } + + .scroll-container { + flex: auto; + overflow-y: auto; + } + + .clear-icon { + line-height: 24px; + padding: 0 10px; + cursor: pointer; + } + + /deep/ .el-input--mini .el-input__inner { + height: 24px; + line-height: 24px; + border: none; + border-radius: unset; + } + + .label-select { + flex: auto; + } + + /deep/ .label-select .el-input__inner { + padding-left: 0 !important; + min-width: 180px; + } + + .list-container { + white-space: nowrap; + width: 100%; + } + + .search-icon { + line-height: 26px; + padding: 0 10px; + cursor: pointer; + border-radius: 0 4px 4px 0; + + text-align: center; + background: #31739C; + color: #ffffff; + } + + .search-icon:hover { + background: #2d4b6f; + color: #fff; + } + + /deep/ input { + outline: none; + box-shadow: none !important; + } + + +</style> + + diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/RecentSearch.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/RecentSearch.vue new file mode 100644 index 0000000..a6338b3 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/RecentSearch.vue @@ -0,0 +1,103 @@ +<template> + <el-popover + :popper-append-to-body="true" + popper-class="RecentSearch" + placement="bottom-start" + trigger="hover" + width="160" + v-model="visible"> + <div class="list-container" > + <template v-if="historyList.length>0"> + <template v-for="(item,index) in historyList"> + <div class="el-dropdown-menu__item history-item" :id="'historyItem'+index" v-idscope @click="handleSelect(item)"> + <template v-for="(condition,conditionIndex) in item"> + <template v-if="conditionIndex>0">;</template>{{ condition.name }} = {{ formatVal(condition.value,condition.options) }} + </template> + </div> + </template> + </template> + <template v-else> + <div class="history-item">{{$t('i18n.overall.searchInfo.noData')}} </div> + </template> + </div> + <div class="clear-all el-dropdown-menu__item" id="clearHistory" @click="handleClear">{{ $t('i18n.overall.searchInfo.clearHistory') }}</div> + <i class="el-icon-time history-icon" slot="reference"></i> + </el-popover> +</template> + +<script> + import searchHistory from './historyApi' + export default { + name: "RecentSearch", + data() { + return { + visible: false, + historyList:[] + } + }, + mounted() { + + }, + methods:{ + formatVal(val,options){ + if(val && Array.isArray(val)){ + return val.join(' - ') + } + if(options && Array.isArray(options)){ + var selectItem=options.find(item=>{ + return item.value === val + }) + return selectItem ? selectItem.label : val + } + return val + }, + handleClear(){ + searchHistory.clearPageHistory(this.$parent.historyKey) + this.getHistotyList() + this.visible=false + }, + handleSelect(item){ + //选中一条历史记录 回调函数... + this.$emit("selectHistory",item) + this.visible=false + }, + getHistotyList(){ + this.historyList=searchHistory.getPageHistory(this.$parent.historyKey) + } + }, + watch:{ + visible:{ + handler(n,o){ + this.getHistotyList() + }, + immediate:false, + deep:false + } + } + } +</script> + +<style scoped> + .history-icon { + padding: 0 10px; + cursor: pointer; + line-height: 24px; + } + .list-container{ + max-height: 300px; + overflow-y: auto; + } + .clear-all{ + font-size: 12px; + line-height: 32px; + text-align: center; + border-top: 1px solid #DCDFE6; + cursor: pointer; + } + .history-item{ + line-height: 28px; + padding: 0 20px; + text-align: left; + font-size: 12px; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/SearchItem.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/SearchItem.vue new file mode 100644 index 0000000..1cdf097 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/SearchItem.vue @@ -0,0 +1,343 @@ +<template> + <div class="ListItem clearfix" :class="{'last-item':isLast && isFocus}"> + <!-- label 标签 --> + <div class="label"> + <span class="el-tag el-tag--info el-tag--mini el-tag--light" @click.stop="editlabel"> + <span class="el-select__tags-text">{{ label }}</span> + </span> + </div> + <!-- value 标签 --> + <div class="value" v-show="!isFocus" :class="{'none': !value || ( Array.isArray(value) && value.length<=0)}"> + <span class="el-tag el-tag--info el-tag--mini el-tag--light" @click.stop="editVal"> + <el-tooltip class="item" effect="light" :content="getVal(value,selectItem.type || 'input')" placement="bottom"> + <span class="el-select__tags-text">{{ getVal(value,selectItem.type || 'input') }}</span> + </el-tooltip> + <i class="el-tag__close el-icon-close" @click.stop="handleDel"></i> + </span> + </div> + <!-- 输入框操作项 --> + <div class="input-item" v-show="isFocus"> + <template v-if="type==='timeRange'"> + <v-timerange + @move="handleMove" + @del="handleDel" + @focus="handleFocus" + @blur="handleBlur" + @keydown="handleKeydown" + @active="handleActive" + ref="item" + class="input" + :placeholder="placeholder" + v-model="value"/> + </template> + <template v-else-if="type === 'select'"> + <v-select + @move="handleMove" + @active="handleActive" + @del="handleDel" + @focus="handleFocus" + @blur="handleBlur" + @keydown="handleKeydown" + ref="item" + class="input" + :popper-append-to-body="false" + popper-class="autocomplete-popover" + :placeholder="placeholder" + v-model="value" + :options="selectItem.options"/> + </template> + <template v-else> + <v-input + @move="handleMove" + @active="handleActive" + @del="handleDel" + @focus="handleFocus" + @blur="handleBlur" + @keydown="handleKeydown" + ref="item" + class="input" + :popper-append-to-body="false" + popper-class="autocomplete-popover" + v-model="value" + :maxlength="255" + :placeholder="placeholder"/> + </template> + </div> + </div> +</template> + +<script> + import VPicker from './VPicker.vue' + import VInput from './VInput.vue' + import VTimerange from './VTimerange.vue' + import VSelect from './VSelect.vue' + + var timer=null + export default { + name: "ListItem", + props: ['selectItem', "isLast", 'currentIndex'], + data() { + return { + loading: "", + isFocus: false, + placeholder: "", + label: "", + type: "", //time timeRange select input ,当前输入框类型 + } + }, + created() { + this.label = this.selectItem.name || null; + this.type = this.selectItem.type || null; + this.placeholder = this.selectItem.placeholder || null + }, + mounted() { + //新增一项数据 直接触发聚焦事件 + + }, + methods: { + clickItem(){ + setTimeout(()=>{ + this.$emit('clickItem') + }) + }, + handleMove(direction) { + //direction left right 移动方向 ... + setTimeout(()=>{ + if (direction === 'left') { + if (this.currentIndex) { + this.$emit('moveTo', { + self:this, + toIndex: this.currentIndex - 1, + }) + } + } else { + this.$emit('moveTo', { + self:this, + toIndex: this.currentIndex + 1, + }) + } + }) + }, + handleActive() { + //会执行 多次,但是不会影响功能 + this.$emit('active', { + currentIndex: this.currentIndex, + currentItem: this.selectItem + }) + }, + visibleChangeHandle() { + //输入框 可能需要异步请求接口 + }, + getVal(value, type = 'input') { + if (type === 'timeRange' && value) { + return value.join(' - ') + } + if (type === 'select' && value) { + var selItem=this.selectItem.options.find((item,index)=>{ + return item.value === value + }) + return (selItem && selItem.label) || value + } + return value + }, + handleFocus() { + this.isFocus = true; //修改当前组件的 操作状态 + this.$parent.conditionConfig.isShow = false; //展示 搜索的字段 + this.$parent.isFocus = true; + this.$refs.item && this.$refs.item.triggerFocus() //触发 光标移入 或者下拉 ... + }, + handleBlur() { + + if(this.type=='timeRange'){ + var time1 = this.value[0] + var time2 = this.value[1] + if(new Date(time1).getTime()==new Date(time2).getTime()){ + this.$message.error(this.$t('i18n.overall.other.dateTimeTips')); + this.handleFocus(); + return false + } + } + + this.isFocus = false; + this.$parent.isFocus = false; + this.$parent.conditionConfig.isShow = true; + + clearTimeout(timer) + timer=setTimeout(()=>{ + this.$parent.triggerFocus() + clearTimeout(timer) + },300) + }, + handleKeydown() { + var keyCode = window.event ? e.keyCode : e.which; + //删除事件 + if (keyCode === 8) { //删除 + + } + if (keyCode === 13) { //回车 + + } + }, + handleClear() { + //清空所有 选中内容 + if (this.type === 'timeRange') { + this.value = []; + return + } + this.value = "" + }, + handleDel() { + this.$emit("del", this.selectItem) + this.clickItem() + }, + editVal() { + //编辑值 + this.isFocus = true; + this.$parent.isFocus = true; + this.$parent.conditionConfig.isShow = false; + this.$refs.item && this.$refs.item.triggerFocus() + this.clickItem() + }, + editlabel() { + //编辑label + this.isFocus = true; + this.$parent.isFocus = true; + this.$parent.conditionConfig.isShow = false; + this.$refs.item && this.$refs.item.triggerFocus() + this.clickItem() + } + }, + computed: { + value: { + get() { + return this.selectItem.value + }, + set(val) { + // this.selectItem.value = val + this.$set(this.selectItem, 'value',val) + } + } + }, + components: { + VPicker, + VInput, + VTimerange, + VSelect, + }, + destroyed() { + clearTimeout(timer); + timer=null + }, + deactivated() { + clearTimeout(timer); + timer=null + } + } +</script> + +<style lang="less" scoped> + .input-item { + flex: auto; + } + + .input-item .input { + width: 100%; + } + + /deep/ .input-item input { + min-width: 200px; + width: 100%; + border: none; + box-shadow: none; + } + + + /deep/ .autocomplete-popover { + width: auto !important; + max-width: 300px !important; + } + + /deep/ .input .el-input__inner { + font-size: 12px; + height: 24px; + line-height: 24px; + padding: 0 2px; + } + + .ListItem { + font-size: 0; + margin-right: 8px; + display: flex; + } + + .ListItem div { + /*float: left;*/ + white-space: nowrap; + display: inline-block; + } + + .clearfix:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; + } + + .label { + margin: 1px; + } + + .value { + margin: 1px; + } + + .el-tag { + height: 16px; + line-height: 16px; + } + + .ListItem:hover .el-tag.el-tag--info { + background-color: #DFDFDF; + } + + .el-tag.el-tag--info { + background-color: #f4f4f5; + } + + /* 空数据 */ + .none .el-tag { + padding: 0; + } + + .none .el-tag .el-tag__close { + left: 0px; + /*top: -1px;*/ + } + + .last-item { + display: flex; + flex: auto; + } + + .el-tag { + vertical-align: middle; + box-sizing: inherit; + } + + .el-select__tags-text { + vertical-align: unset; + float: none !important; + } + + .el-tag .el-icon-close { + /*top: -5px*/ + vertical-align: top; + top:0; + } + + + /deep/ .item { + max-width: 240px; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/TrimInput.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/TrimInput.vue new file mode 100644 index 0000000..f126f2c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/TrimInput.vue @@ -0,0 +1,88 @@ +<template> + <!-- input 类型 --> + <el-input + :type="type" + class="rel-input trim-input" + ref="input" + :maxlength="maxlength" + :autoComplete="autoComplete || 'on'" + autosize + v-model="valCopy" + @keydown.native="handleKeydown" + :placeholder="placeholder || $t('i18n.overall.placeholder.enter')" + @blur="trim" + :disabled='disabled' + @input="handleName" + v-bind="$attrs" + :rows="rows" + :show-word-limit="showWordLimit" + :id="$attrs.id+'1'" + > + </el-input> +</template> + +<script> + import getTxt1CursorPosition from './cursorPosition' + import lodashCloneDeep from 'lodash/cloneDeep' + + export default { + name: "Trim-input", + data() { + return { + valCopy: null, + } + }, + props: ['specialCharacters','value', 'type', 'rows', 'disabled', 'maxlength', 'autoComplete', 'showPassword', 'placeholder', 'showWordLimit'], + model: { + prop: 'value', + event: 'change' + }, + created() { + this.valCopy = lodashCloneDeep(this.value) + }, + mounted() { + }, + methods: { + trim(){ + if(this.valCopy!==''&&this.valCopy!=null){ + this.valCopy = this.valCopy.replace(/(^\s*)|(\s*$)/g, "") + } + this.$emit('blur', this.valCopy) + }, + handleKeydown(e) { + if(!this.specialCharacters){ + this.valCopy = this.valCopy.replace(/(^\s*)/g, "") + } + this.$emit('change', this.valCopy) + }, + handleName(){ + if(this.specialCharacters){ + let name = this.profileName_regular(this.valCopy) + this.valCopy = name.replace(/(^\s*)/g, "") + } + this.$emit('input',this.valCopy) + }, + }, + watch: { + valCopy(n, o) { + if (this.value !== n) { + this.$emit('change', this.valCopy) + } + }, + value(n, o) { + this.valCopy = n + } + } + } +</script> + +<style lang="less" scoped> + /deep/ .el-input__inner { + padding-left: 10px !important; + min-width: 180px; + font-size: 12px; + } + /deep/ .el-textarea__inner{ + height: auto !important; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VAutoInput.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VAutoInput.vue new file mode 100644 index 0000000..049f200 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VAutoInput.vue @@ -0,0 +1,16 @@ +<template> + <!-- 带搜索建议的下拉 --> + <div class="VAutoInput"> + + </div> +</template> + +<script> + export default { + name: "VAutoInput" + } +</script> + +<style lang="less" scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VInput.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VInput.vue new file mode 100644 index 0000000..31cd2a5 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VInput.vue @@ -0,0 +1,97 @@ +<template> + <!-- input 类型 --> + <el-input size="mini" + class="rel-input v-input" + ref="input" + :maxlength="255" + :autoComplete="autoComplete || 'off'" + autosize + v-bind="$props" + v-on="$listeners" + v-model="valCopy" + @keydown.native="handleKeydown" + :placeholder="placeholder || $t('i18n.overall.searchInfo.inputVal')" + > + </el-input> +</template> + +<script> + import getTxt1CursorPosition from './cursorPosition' + import lodashCloneDeep from 'lodash/cloneDeep' + + export default { + name: "v-input", + data() { + return { + valCopy: null, + } + }, + props: ['value', 'type', 'rows', 'disabled', 'maxlength', 'autoComplete', 'showPassword', 'placeholder'], + model: { + prop: 'value', + event: 'change' + }, + created() { + this.valCopy = lodashCloneDeep(this.value) + }, + mounted() { + }, + methods: { + handleKeydown(e) { + var dom = this.$refs.input ? $(this.$refs.input.$el).find('input')[0] : ''; + var cursorIndex = dom ? getTxt1CursorPosition(dom, document) || 0 : 0; + var keyCode = window.event ? e.keyCode : e.which; + //删除事件 + if (keyCode === 8) { + if (this.valCopy === "" || this.valCopy == null) { + this.$emit("del") + } + return + } + if (keyCode === 13) { //回车 + this.$emit("blur") + return + } + + if (keyCode === 37) { //左箭头 || 37 右箭头 + if (dom && cursorIndex === 0) { + this.$emit("move", 'left') + } + return + } + if (keyCode === 39) { //右箭头 || 39 右箭头 + if (!this.valCopy || cursorIndex === this.valCopy.length) { + this.$emit("move", 'right') + } + return + } + }, + triggerFocus() { + this.$emit("active") + this.$nextTick(() => { + //并非 触发聚焦事件 而是光标移入 类似 + var dom = this.$refs.input.$el.children[0]; //获取输入框DOM 索引 + dom.focus(); + }) + } + }, + watch: { + valCopy(n, o) { + if (this.value !== n) { + this.$emit('change', this.valCopy) + } + }, + value(n, o) { + this.valCopy = n + } + } + } +</script> + +<style lang="less" scoped> + /deep/ .el-input__inner { + padding-left: 0 !important; + min-width: 180px; + font-size: 12px; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VPicker.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VPicker.vue new file mode 100644 index 0000000..497280c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VPicker.vue @@ -0,0 +1,18 @@ +<template> + <!-- 单个时间选择器(暂不开发) --> + <div class="v-picker"> + </div> +</template> + +<script> + import lodashCloneDeep from 'lodash/cloneDeep' + + export default { + name: "v-picker", + + } +</script> + +<style lang="" scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VSelect.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VSelect.vue new file mode 100644 index 0000000..5572a6c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VSelect.vue @@ -0,0 +1,149 @@ +<template> + <!-- 暂时不支持 异步,关联下拉 需要的话 请在该组件改写 --> + <el-select + :popper-append-to-body="true" + popper-class="select-popper" + @focus.stop + @blur.stop + class="v-select" + ref="select" + :collapse-tags="collapseTags" + size="mini" + autosize + filterable + v-model="valCopy" + @visible-change="visibleChangeHandle" + v-bind="$props" + :loading="loading" + @keydown.native="handleKeydown" + :placeholder="placeholder || $t('i18n.overall.searchInfo.selectVal')" + > + <!--<!–:allow-create="true"–> 根据TSG-9309 问题关闭创建条目需求 后期有其他需求再另加判断--> + <template v-for="(item,index) in optionsCopy"> + <el-option + :id="item.value" + v-idscope + :disabled="item.disabled" + :label="item.label" + :value="item.value"> + </el-option> + </template> + </el-select> +</template> + +<script> + import lodashCloneDeep from 'lodash/cloneDeep' + import getTxt1CursorPosition from "./cursorPosition"; + export default { + name: "v-select", + props: ['value', 'collapseTags', 'options', 'multiple', 'filterable', 'disabled', 'clearable', 'wrapper','placeholder'], + data () { + return { + optionsCopy: [], //下拉框的值 + valCopy: null, //绑定值 + loading: false, + } + }, + model: { + prop: 'value', + event: 'change' + }, + created () { + this.value ? this.valCopy = lodashCloneDeep(this.value) : ''; + this.setOptions() + }, + mounted () { + + }, + methods: { + handleKeydown(e) { + var keyCode = window.event ? e.keyCode : e.which; + var dom =this.$refs.select ? $(this.$refs.select.$el).find('input')[0] :''; + var cursorIndex = dom ? getTxt1CursorPosition(dom, document) || 0 : 0; + //删除事件 + if (keyCode === 8) { + if (this.$refs.select.query === "" || this.$refs.select.query == null ) { + this.$emit("blur"); + this.$emit("del") + } + } + // if (keyCode === 13) { //回车 + // this.$emit("blur") + // } + if (keyCode === 37) { //左箭头 || 38 右箭头 + if (dom && cursorIndex === 0) { + this.$refs.select.visible=false + this.$emit("blur") + this.$emit("move", 'left') + } + return + } + if (keyCode === 39) { //左箭头 || 38 右箭头 + if (!this.$refs.select.query || cursorIndex === this.$refs.select.query.length) { + this.$refs.select.visible=false + this.$emit("blur") + this.$emit("move", 'right') + } + } + }, + triggerFocus(){ + this.$emit("active") + this.$nextTick(() => { + //触发 下拉事件 + var dom = this.$refs.select.$el.children[0]; //获取输入框DOM 索引 + dom.click(); + }) + // this.$nextTick(() => { + // this.$refs.select.visible=true + // }) + }, + visibleChangeHandle (status) { + //放弃 原生事件, 重写聚焦 失焦事件(原因 里面有个输入框, 不好界定 聚焦 失焦) + if(status === false){ + this.$emit("blur") + }else { + this.$emit("focus") + } + }, + setOptions(){ + this.optionsCopy = this.options ? lodashCloneDeep(this.options) : [] + // if (typeof this.options === Function) { + // this.options=[]; + // this.loading=true; + // this.options().then(options=>{ + // this.loading=false; + // this.optionsCopy =options + // }); + // }else { + // this.optionsCopy = this.options ? lodashCloneDeep(this.options) : [] + // } + } + }, + watch: { + options (n, o) { + //监听下拉数据的变化 + this.optionsCopy = this.options ? [...this.options] : [] + }, + valCopy (n, o) { + if (this.value !== n) { + this.$emit('change', this.valCopy) + } + }, + value (n, o) { + this.valCopy = n + } + } + } +</script> + +<style lang="less" scoped> + .v-select{ + width: auto; + } + /deep/ .el-input__suffix{ + display: none; + } + /deep/ input{ + padding-left: 0 !important; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VTimerange.vue b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VTimerange.vue new file mode 100644 index 0000000..ca891c6 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/VTimerange.vue @@ -0,0 +1,164 @@ +<template> + <!-- 时间范围 --> + <div class="v-timerange" style="position: relative" @click.stop> + <el-input + ref="input" + autosize + size="mini" + @focus="handleFocus" + :placeholder="placeholder || $t('i18n.overall.searchInfo.selectTime')" + @keydown.native="handleKeydown" + v-model="inputVal"/> + <el-date-picker + @change="handleChange" + v-bind="$props" + v-on="$listeners" + format="yyyy-MM-dd HH:mm:ss" + value-format="yyyy-MM-dd HH:mm:ss" + class="time-picker" + size="mini" + ref="timePicker" + :picker-options="pickerOptions" + v-model="valCopy" + type="datetimerange" + start-placeholder="Start Time" + end-placeholder="End Time" + :default-time="['00:00:00','23:59:59']"> + </el-date-picker> + </div> +</template> + +<script> + import Moment from 'moment' + import lodashCloneDeep from 'lodash/cloneDeep' + import getTxt1CursorPosition from "./cursorPosition"; + var dateTime; + export default { + name: "v-timerange", + props: ['value', 'type', 'disabled', 'placeholder'], + data() { + return { + input: '', + valCopy: [], + pickerOptions:{ + }, + } + }, + model: { + prop: 'value', + event: 'change' + }, + methods: { + focus(value){ + console.log(value); + }, + blur(value){ + console.log(value); + }, + handleKeydown(e) { + var keyCode = window.event ? e.keyCode : e.which; + var dom = this.$refs.input ? $(this.$refs.input.$el).find('input')[0] : ''; + var cursorIndex = dom ? getTxt1CursorPosition(dom, document) || 0 : 0; + //删除事件 + if (keyCode === 8) { + this.$emit("del") + this.$emit("blur") + return + } + if (keyCode === 13) { //回车 + this.$refs.timePicker.pickerVisible = false + this.$emit("blur") + return + } + if (keyCode === 37) { //左箭头 || 37 右箭头 + if (dom && cursorIndex === 0) { + this.$refs.timePicker.pickerVisible = false + this.$emit("move", 'left') + } + return + } + if (keyCode === 39) { //右箭头 || 39 右箭头 + if (!this.inputVal || cursorIndex === this.inputVal.length) { + this.$refs.timePicker.pickerVisible = false + this.$emit("move", 'right') + } + return + } + }, + handleChange(value) { + if(value){ + + } + }, + triggerFocus() { + //下拉 日期面板展示 + this.$emit("active") + this.$refs.timePicker.pickerVisible = true; + this.$nextTick(() => { + //并非 触发聚焦事件 而是光标移入 类似 + var dom = this.$refs.input.$el.children[0]; //获取输入框DOM 索引 + dom.focus(); + }) + }, + handleFocus() { + //输入框聚焦 + this.$nextTick(() => { + this.$refs.timePicker.focus() + }) + } + }, + created() { + this.valCopy = this.value ? lodashCloneDeep(this.value) : []; + }, + mounted() { + }, + computed: { + inputVal: { + get() { + var timeVal = this.valCopy || [] + return this.valCopy.join(' - ') + }, + set(val) { + //不允许手动修改时间 校验麻烦 + } + } + }, + watch: { + valCopy(n, o) { + if (this.value !== n) { + this.$emit('change', this.valCopy) + } + }, + value(n, o) { + this.valCopy = n || [] + } + } + } +</script> + +<style lang="less" scoped> + .v-timerange { + position: relative; + } + + .time-picker { + visibility: hidden; + } + + /deep/ .el-date-editor { + position: absolute; + left: 0; + right: 0; + width: auto; + overflow: hidden; + border: none; + padding: 0; + height: 24px; + } + + /deep/ .el-input__inner { + padding-left: 0 !important; + min-width: 248px !important; + font-size: 12px; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/cursorPosition.js b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/cursorPosition.js new file mode 100644 index 0000000..ffe12fd --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/cursorPosition.js @@ -0,0 +1,14 @@ +/* 不能导入导出 global 是不支持document的 */ + +export default function getTxt1CursorPosition(dom,document){ + var oTxt1 =dom + var cursurPosition=-1; + if(oTxt1.selectionStart || oTxt1.selectionStart===0){//非IE浏览器 + cursurPosition= oTxt1.selectionStart; + }else{//IE + var range = document.selection.createRange(); + range.moveStart("character",-oTxt1.value.length); + cursurPosition=range.text.length; + } + return cursurPosition +} diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/historyApi.js b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/historyApi.js new file mode 100644 index 0000000..8b5a305 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/historyApi.js @@ -0,0 +1,86 @@ +import remove from 'lodash/remove' +import Moment from 'moment' +/* 配置文件 */ +import vue from '@/main.js' +import isEqual from 'lodash/isEqual' + +//时间的历史纪录 +class searchHistory { + constructor(key = 'searchHistory', maxLength = 10) { + this.key = key + this.maxLength = maxLength + if (!this.getHistory()) { + localStorage.setItem(this.key, '{}'); + } + } + + getSaveKey() { + //暂时 不这么写 + //获取 页面对应的关键字 , 因为页签的问题, 一个页面 可能出现两个搜索框的问题 .... + var route = vue.$route.path; + return route + } + + getHistory() { + var historyList = JSON.parse(localStorage.getItem(this.key)) + return historyList + } + + getPageHistory(saveKey) { //获取当前页的搜索数据... + var route = saveKey || vue.$route.path; + var historyMap = JSON.parse(localStorage.getItem(this.key)) || {} + return historyMap[route] || [] + } + + setHistory(val) { + localStorage.setItem(this.key, JSON.stringify(val)); + } + + addItem(item, saveKey) { + // var route = vue.$route.name + var route = saveKey || vue.$route.path; //fullPath path name(使用name最好,就是需要改 ) + var historyMap = JSON.parse(localStorage.getItem(this.key)) || {}; + if (!historyMap[route]) { + historyMap[route] = [] + } + + //删除 重复的搜索历史记录 + var itemObj = {} + item.forEach((obj) => { + itemObj[obj.name] = obj.value + }); + historyMap[route] = historyMap[route].filter((historyList, index) => { + var historyItemObj = {}; + historyList.forEach((item) => { + historyItemObj[item.name] = item.value + }); + return !isEqual(itemObj, historyItemObj); + }); + + + // historyMap[route].push(item); + historyMap[route].unshift(item); + + if (historyMap[route].length > this.maxLength) { + historyMap[route].pop() + } + var info = JSON.stringify(historyMap) + localStorage.setItem(this.key, info); + } + + clearPageHistory(saveKey) { + //清除当前 页的搜索数据... + var route = saveKey || vue.$route.path; //fullPath path name(使用name最好,就是需要改 ) + var historyMap = JSON.parse(localStorage.getItem(this.key) || '{}'); + historyMap[route] = [] + var info = JSON.stringify(historyMap) + localStorage.setItem(this.key, info); + } + + clear() { + localStorage.setItem(this.key, '{}'); + } +} + +var history = new searchHistory(); +export default history diff --git a/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/keyboard.js b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/keyboard.js new file mode 100644 index 0000000..9f3ee00 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/FilteredSearch/components/keyboard.js @@ -0,0 +1,31 @@ +export function fireKeyEvent(el, evtType, keyCode) { + var evtObj; + if (document.createEvent) { + if (window.KeyEvent) {//firefox 浏览器下模拟事件 + evtObj = document.createEvent('KeyEvents'); + evtObj.initKeyEvent(evtType, true, true, window, true, false, false, false, keyCode, 0); + } else {//chrome 浏览器下模拟事件 + evtObj = document.createEvent('UIEvents'); + evtObj.initUIEvent(evtType, true, true, window, 1); + + delete evtObj.keyCode; + if (typeof evtObj.keyCode === "undefined") {//为了模拟keycode + Object.defineProperty(evtObj, "keyCode", { value: keyCode }); + } else { + evtObj.key = String.fromCharCode(keyCode); + } + + if (typeof evtObj.ctrlKey === 'undefined') {//为了模拟ctrl键 + Object.defineProperty(evtObj, "ctrlKey", { value: true }); + } else { + evtObj.ctrlKey = true; + } + } + el.dispatchEvent(evtObj); + + } else if (document.createEventObject) {//IE 浏览器下模拟事件 + evtObj = document.createEventObject(); + evtObj.keyCode = keyCode + el.fireEvent('on' + evtType, evtObj); + } +} diff --git a/UI source code/dns_mapping_ui-master/src/components/GithubCorner/index.vue b/UI source code/dns_mapping_ui-master/src/components/GithubCorner/index.vue new file mode 100644 index 0000000..bc79cbf --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/GithubCorner/index.vue @@ -0,0 +1,54 @@ +<template> + <a href="https://github.com/elunez/eladmin" target="_blank" class="github-corner" aria-label="View source on Github"> + <svg + width="80" + height="80" + viewBox="0 0 250 250" + style="fill:#40c9c6; color:#fff;" + aria-hidden="true" + > + <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" /> + <path + d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" + fill="currentColor" + style="transform-origin: 130px 106px;" + class="octo-arm" + /> + <path + d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" + fill="currentColor" + class="octo-body" + /> + </svg> + </a> +</template> + +<style scoped> +.github-corner:hover .octo-arm { + animation: octocat-wave 560ms ease-in-out +} + +@keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0) + } + 20%, + 60% { + transform: rotate(-25deg) + } + 40%, + 80% { + transform: rotate(10deg) + } +} + +/* @media (max-width:500px) { + .github-corner:hover .octo-arm { + animation: none + } + .github-corner .octo-arm { + animation: octocat-wave 560ms ease-in-out + } +} */ +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Hamburger/index.vue b/UI source code/dns_mapping_ui-master/src/components/Hamburger/index.vue new file mode 100644 index 0000000..368b002 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Hamburger/index.vue @@ -0,0 +1,44 @@ +<template> + <div style="padding: 0 15px;" @click="toggleClick"> + <svg + :class="{'is-active':isActive}" + class="hamburger" + viewBox="0 0 1024 1024" + xmlns="http://www.w3.org/2000/svg" + width="64" + height="64" + > + <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" /> + </svg> + </div> +</template> + +<script> +export default { + name: 'Hamburger', + props: { + isActive: { + type: Boolean, + default: false + } + }, + methods: { + toggleClick() { + this.$emit('toggleClick') + } + } +} +</script> + +<style scoped> +.hamburger { + display: inline-block; + vertical-align: middle; + width: 20px; + height: 20px; +} + +.hamburger.is-active { + transform: rotate(180deg); +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/HeaderSearch/index.vue b/UI source code/dns_mapping_ui-master/src/components/HeaderSearch/index.vue new file mode 100644 index 0000000..c713efc --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/HeaderSearch/index.vue @@ -0,0 +1,188 @@ +<template> + <div :class="{'show':show}" class="header-search"> + <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" /> + <el-select + ref="headerSearchSelect" + v-model="search" + :remote-method="querySearch" + filterable + default-first-option + remote + placeholder="Search" + class="header-search-select" + @change="change" + > + <el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" /> + </el-select> + </div> +</template> + +<script> +// fuse is a lightweight fuzzy-search module +// make search results more in line with expectations +import Fuse from 'fuse.js' +import path from 'path' + +export default { + name: 'HeaderSearch', + data() { + return { + search: '', + options: [], + searchPool: [], + show: false, + fuse: undefined + } + }, + computed: { + routes() { + return this.$store.state.permission.routers + } + }, + watch: { + routes() { + this.searchPool = this.generateRoutes(this.routes) + }, + searchPool(list) { + this.initFuse(list) + }, + show(value) { + if (value) { + document.body.addEventListener('click', this.close) + } else { + document.body.removeEventListener('click', this.close) + } + } + }, + mounted() { + this.searchPool = this.generateRoutes(this.routes) + }, + methods: { + click() { + this.show = !this.show + if (this.show) { + this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus() + } + }, + close() { + this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur() + this.options = [] + this.show = false + }, + change(val) { + if (this.ishttp(val.path)) { + // http(s):// 路径新窗口打开 + window.open(val.path, '_blank') + } else { + this.$router.push(val.path) + } + this.search = '' + this.options = [] + this.$nextTick(() => { + this.show = false + }) + }, + initFuse(list) { + this.fuse = new Fuse(list, { + shouldSort: true, + threshold: 0.4, + location: 0, + distance: 100, + maxPatternLength: 32, + minMatchCharLength: 1, + keys: [{ + name: 'title', + weight: 0.7 + }, { + name: 'path', + weight: 0.3 + }] + }) + }, + // Filter out the routes that can be displayed in the sidebar + // And generate the internationalized title + generateRoutes(routes, basePath = '/', prefixTitle = []) { + let res = [] + + for (const router of routes) { + // skip hidden router + if (router.hidden) { continue } + + const data = { + path: !this.ishttp(router.path) ? path.resolve(basePath, router.path) : router.path, + title: [...prefixTitle] + } + + if (router.meta && router.meta.title) { + data.title = [...data.title, router.meta.title] + + if (router.redirect !== 'noRedirect') { + // only push the routes with title + // special case: need to exclude parent router without redirect + res.push(data) + } + } + + // recursive child routes + if (router.children) { + const tempRoutes = this.generateRoutes(router.children, data.path, data.title) + if (tempRoutes.length >= 1) { + res = [...res, ...tempRoutes] + } + } + } + return res + }, + querySearch(query) { + if (query !== '') { + this.options = this.fuse.search(query) + } else { + this.options = [] + } + }, + ishttp(url) { + return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1 + } + } +} +</script> + +<style lang="scss" scoped> +.header-search { + font-size: 0 !important; + + .search-icon { + cursor: pointer; + font-size: 18px; + vertical-align: middle; + } + + .header-search-select { + font-size: 18px; + transition: width 0.2s; + width: 0; + overflow: hidden; + background: transparent; + border-radius: 0; + display: inline-block; + vertical-align: middle; + + ::v-deep .el-input__inner { + border-radius: 0; + border: 0; + padding-left: 0; + padding-right: 0; + box-shadow: none !important; + border-bottom: 1px solid #d9d9d9; + vertical-align: middle; + } + } + + &.show { + .header-search-select { + width: 210px; + margin-left: 10px; + } + } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/IconSelect/index.vue b/UI source code/dns_mapping_ui-master/src/components/IconSelect/index.vue new file mode 100644 index 0000000..b0ec9fa --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/IconSelect/index.vue @@ -0,0 +1,68 @@ +<!-- @author zhengjie --> +<template> + <div class="icon-body"> + <el-input v-model="name" style="position: relative;" clearable placeholder="请输入图标名称" @clear="filterIcons" @input.native="filterIcons"> + <i slot="suffix" class="el-icon-search el-input__icon" /> + </el-input> + <div class="icon-list"> + <div v-for="(item, index) in iconList" :key="index" @click="selectedIcon(item)"> + <svg-icon :icon-class="item" style="height: 30px;width: 16px;" /> + <span>{{ item }}</span> + </div> + </div> + </div> +</template> + +<script> +import icons from './requireIcons' +export default { + name: 'IconSelect', + data() { + return { + name: '', + iconList: icons + } + }, + methods: { + filterIcons() { + this.iconList = icons + if (this.name) { + this.iconList = this.iconList.filter(item => item.includes(this.name)) + } + }, + selectedIcon(name) { + this.$emit('selected', name) + document.body.click() + }, + reset() { + this.name = '' + this.iconList = icons + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> + .icon-body { + width: 100%; + padding: 10px; + .icon-list { + height: 200px; + overflow-y: scroll; + div { + height: 30px; + line-height: 30px; + margin-bottom: -5px; + cursor: pointer; + width: 33%; + float: left; + } + span { + display: inline-block; + vertical-align: -0.15em; + fill: currentColor; + overflow: hidden; + } + } + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/IconSelect/requireIcons.js b/UI source code/dns_mapping_ui-master/src/components/IconSelect/requireIcons.js new file mode 100644 index 0000000..99e5c54 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/IconSelect/requireIcons.js @@ -0,0 +1,11 @@ + +const req = require.context('../../assets/icons/svg', false, /\.svg$/) +const requireAll = requireContext => requireContext.keys() + +const re = /\.\/(.*)\.svg/ + +const icons = requireAll(req).map(i => { + return i.match(re)[1] +}) + +export default icons diff --git a/UI source code/dns_mapping_ui-master/src/components/Iframe/index.vue b/UI source code/dns_mapping_ui-master/src/components/Iframe/index.vue new file mode 100644 index 0000000..9f395a3 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Iframe/index.vue @@ -0,0 +1,30 @@ +<template> + <div v-loading="loading" :style="'height:'+ height"> + <iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" /> + </div> +</template> +<script> +export default { + props: { + src: { + type: String, + required: true + } + }, + data() { + return { + height: document.documentElement.clientHeight - 94.5 + 'px;', + loading: true + } + }, + mounted: function() { + setTimeout(() => { + this.loading = false + }, 230) + const that = this + window.onresize = function temp() { + that.height = document.documentElement.clientHeight - 94.5 + 'px;' + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/JavaEdit/index.vue b/UI source code/dns_mapping_ui-master/src/components/JavaEdit/index.vue new file mode 100644 index 0000000..c703829 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/JavaEdit/index.vue @@ -0,0 +1,78 @@ +<template> + <div class="json-editor"> + <textarea ref="textarea" /> + </div> +</template> + +<script> +import CodeMirror from 'codemirror' +import 'codemirror/lib/codemirror.css' +// 替换主题这里需修改名称 +import 'codemirror/theme/idea.css' +import 'codemirror/mode/clike/clike' +export default { + props: { + value: { + type: String, + required: true + }, + height: { + type: String, + required: true + } + }, + data() { + return { + editor: false + } + }, + watch: { + value(value) { + const editorValue = this.editor.getValue() + if (value !== editorValue) { + this.editor.setValue(this.value) + } + }, + height(value) { + this.editor.setSize('auto', this.height) + } + }, + mounted() { + this.editor = CodeMirror.fromTextArea(this.$refs.textarea, { + mode: 'text/x-java', + lineNumbers: true, + lint: true, + lineWrapping: true, + tabSize: 2, + cursorHeight: 0.9, + // 替换主题这里需修改名称 + theme: 'idea', + readOnly: true + }) + this.editor.setSize('auto', this.height) + this.editor.setValue(this.value) + }, + methods: { + getValue() { + return this.editor.getValue() + } + } +} +</script> + +<style scoped> + .json-editor{ + height: 100%; + margin-bottom: 10px; + } + .json-editor >>> .CodeMirror { + font-size: 14px; + overflow-y:auto; + font-weight:normal + } + .json-editor >>> .CodeMirror-scroll{ + } + .json-editor >>> .cm-s-rubyblue span.cm-string { + color: #F08047; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Pagination/index.vue b/UI source code/dns_mapping_ui-master/src/components/Pagination/index.vue new file mode 100644 index 0000000..c815e13 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Pagination/index.vue @@ -0,0 +1,101 @@ +<template> + <div :class="{'hidden':hidden}" class="pagination-container"> + <el-pagination + :background="background" + :current-page.sync="currentPage" + :page-size.sync="pageSize" + :layout="layout" + :page-sizes="pageSizes" + :total="total" + v-bind="$attrs" + @size-change="handleSizeChange" + @current-change="handleCurrentChange" + /> + </div> +</template> + +<script> +import { scrollTo } from '@/utils/scroll-to' + +export default { + name: 'Pagination', + props: { + total: { + required: true, + type: Number + }, + page: { + type: Number, + default: 1 + }, + limit: { + type: Number, + default: 20 + }, + pageSizes: { + type: Array, + default() { + return [10, 20, 30, 50] + } + }, + layout: { + type: String, + default: 'total, sizes, prev, pager, next, jumper' + }, + background: { + type: Boolean, + default: true + }, + autoScroll: { + type: Boolean, + default: true + }, + hidden: { + type: Boolean, + default: false + } + }, + computed: { + currentPage: { + get() { + return this.page + }, + set(val) { + this.$emit('update:page', val) + } + }, + pageSize: { + get() { + return this.limit + }, + set(val) { + this.$emit('update:limit', val) + } + } + }, + methods: { + handleSizeChange(val) { + this.$emit('pagination', { page: this.currentPage, limit: val }) + if (this.autoScroll) { + scrollTo(0, 800) + } + }, + handleCurrentChange(val) { + this.$emit('pagination', { page: val, limit: this.pageSize }) + if (this.autoScroll) { + scrollTo(0, 800) + } + } + } +} +</script> + +<style scoped> +.pagination-container { + background: #fff; + padding: 32px 16px; +} +.pagination-container.hidden { + display: none; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/PanThumb/index.vue b/UI source code/dns_mapping_ui-master/src/components/PanThumb/index.vue new file mode 100644 index 0000000..de6940a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/PanThumb/index.vue @@ -0,0 +1,140 @@ +<template> + <div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item"> + <div class="pan-info"> + <div class="pan-info-roles-container"> + <slot /> + </div> + </div> + <img :src="image" class="pan-thumb"> + </div> +</template> + +<script> +export default { + name: 'PanThumb', + props: { + image: { + type: String, + required: true + }, + zIndex: { + type: Number, + default: 1 + }, + width: { + type: String, + default: '150px' + }, + height: { + type: String, + default: '150px' + } + } +} +</script> + +<style scoped> +.pan-item { + width: 200px; + height: 200px; + border-radius: 50%; + display: inline-block; + position: relative; + cursor: default; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); +} + +.pan-info-roles-container { + padding: 20px; + text-align: center; +} + +.pan-thumb { + width: 100%; + height: 100%; + background-size: 100%; + border-radius: 50%; + overflow: hidden; + position: absolute; + transform-origin: 95% 40%; + transition: all 0.3s ease-in-out; +} + +.pan-thumb:after { + content: ''; + width: 8px; + height: 8px; + position: absolute; + border-radius: 50%; + top: 40%; + left: 95%; + margin: -4px 0 0 -4px; + background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%); + box-shadow: 0 0 1px rgba(255, 255, 255, 0.9); +} + +.pan-info { + position: absolute; + width: inherit; + height: inherit; + border-radius: 50%; + overflow: hidden; + box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05); +} + +.pan-info h3 { + color: #fff; + text-transform: uppercase; + position: relative; + letter-spacing: 2px; + font-size: 18px; + margin: 0 60px; + padding: 22px 0 0 0; + height: 85px; + font-family: 'Open Sans', Arial, sans-serif; + text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3); +} + +.pan-info p { + color: #fff; + padding: 10px 5px; + font-style: italic; + margin: 0 30px; + font-size: 12px; + border-top: 1px solid rgba(255, 255, 255, 0.5); +} + +.pan-info p a { + display: block; + color: #333; + width: 80px; + height: 80px; + background: rgba(255, 255, 255, 0.3); + border-radius: 50%; + color: #fff; + font-style: normal; + font-weight: 700; + text-transform: uppercase; + font-size: 9px; + letter-spacing: 1px; + padding-top: 24px; + margin: 7px auto 0; + font-family: 'Open Sans', Arial, sans-serif; + opacity: 0; + transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s; + transform: translateX(60px) rotate(90deg); +} + +.pan-info p a:hover { + background: rgba(255, 255, 255, 0.5); +} + +.pan-item:hover .pan-thumb { + transform: rotate(-110deg); +} + +.pan-item:hover .pan-info p a { + opacity: 1; + transform: translateX(0px) rotate(0deg); +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/ParentView/index.vue b/UI source code/dns_mapping_ui-master/src/components/ParentView/index.vue new file mode 100644 index 0000000..98240ae --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/ParentView/index.vue @@ -0,0 +1,3 @@ +<template> + <router-view /> +</template> diff --git a/UI source code/dns_mapping_ui-master/src/components/Permission/index.js b/UI source code/dns_mapping_ui-master/src/components/Permission/index.js new file mode 100644 index 0000000..e5dadd3 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Permission/index.js @@ -0,0 +1,13 @@ +import permission from './permission' + +const install = function(Vue) { + Vue.directive('permission', permission) +} + +if (window.Vue) { + window['permission'] = permission + Vue.use(install); // eslint-disable-line +} + +permission.install = install +export default permission diff --git a/UI source code/dns_mapping_ui-master/src/components/Permission/permission.js b/UI source code/dns_mapping_ui-master/src/components/Permission/permission.js new file mode 100644 index 0000000..9a6ba28 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Permission/permission.js @@ -0,0 +1,21 @@ +import store from '@/store' + +export default { + inserted(el, binding) { + const { value } = binding + const roles = store.getters && store.getters.roles + if (value && value instanceof Array) { + if (value.length > 0) { + const permissionRoles = value + const hasPermission = roles.some(role => { + return permissionRoles.includes(role) + }) + if (!hasPermission) { + el.parentNode && el.parentNode.removeChild(el) + } + } + } else { + throw new Error(`使用方式: v-permission="['admin','editor']"`) + } + } +} diff --git a/UI source code/dns_mapping_ui-master/src/components/RightPanel/index.vue b/UI source code/dns_mapping_ui-master/src/components/RightPanel/index.vue new file mode 100644 index 0000000..b65ecec --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/RightPanel/index.vue @@ -0,0 +1,149 @@ +<template> + <div ref="rightPanel" :class="{show:show}" class="rightPanel-container"> + <div class="rightPanel-background" /> + <div class="rightPanel"> + <div class="rightPanel-items"> + <slot /> + </div> + </div> + </div> +</template> + +<script> +import { addClass, removeClass } from '@/utils' + +export default { + name: 'RightPanel', + props: { + clickNotClose: { + default: false, + type: Boolean + }, + buttonTop: { + default: 250, + type: Number + } + }, + computed: { + show: { + get() { + return this.$store.state.settings.showSettings + }, + set(val) { + this.$store.dispatch('settings/changeSetting', { + key: 'showSettings', + value: val + }) + } + }, + theme() { + return this.$store.state.settings.theme + } + }, + watch: { + show(value) { + if (value && !this.clickNotClose) { + this.addEventClick() + } + if (value) { + addClass(document.body, 'showRightPanel') + } else { + removeClass(document.body, 'showRightPanel') + } + } + }, + mounted() { + this.insertToBody() + this.addEventClick() + }, + beforeDestroy() { + const elx = this.$refs.rightPanel + elx.remove() + }, + methods: { + addEventClick() { + window.addEventListener('click', this.closeSidebar) + }, + closeSidebar(evt) { + const parent = evt.target.closest('.rightPanel') + if (!parent) { + this.show = false + window.removeEventListener('click', this.closeSidebar) + } + }, + insertToBody() { + const elx = this.$refs.rightPanel + const body = document.querySelector('body') + body.insertBefore(elx, body.firstChild) + } + } +} +</script> + +<style> + .showRightPanel { + overflow: hidden; + position: relative; + width: calc(100% - 15px); + } +</style> + +<style lang="scss" scoped> + .rightPanel-background { + position: fixed; + top: 0; + left: 0; + opacity: 0; + transition: opacity .3s cubic-bezier(.7, .3, .1, 1); + background: rgba(0, 0, 0, .2); + z-index: -1; + } + + .rightPanel { + width: 100%; + max-width: 260px; + height: 100vh; + position: fixed; + top: 0; + right: 0; + box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05); + transition: all .25s cubic-bezier(.7, .3, .1, 1); + transform: translate(100%); + background: #fff; + z-index: 40000; + } + + .show { + transition: all .3s cubic-bezier(.7, .3, .1, 1); + + .rightPanel-background { + z-index: 20000; + opacity: 1; + width: 100%; + height: 100%; + } + + .rightPanel { + transform: translate(0); + } + } + + .handle-button { + width: 48px; + height: 48px; + position: absolute; + left: -48px; + text-align: center; + font-size: 24px; + border-radius: 6px 0 0 6px !important; + z-index: 0; + pointer-events: auto; + cursor: pointer; + color: #fff; + line-height: 48px; + i { + font-size: 24px; + line-height: 48px; + } + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Screenfull/index.vue b/UI source code/dns_mapping_ui-master/src/components/Screenfull/index.vue new file mode 100644 index 0000000..260c90d --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Screenfull/index.vue @@ -0,0 +1,60 @@ +<template> + <div> + <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" /> + </div> +</template> + +<script> +import screenfull from 'screenfull' + +export default { + name: 'Screenfull', + data() { + return { + isFullscreen: false + } + }, + mounted() { + this.init() + }, + beforeDestroy() { + this.destroy() + }, + methods: { + click() { + if (!screenfull.enabled) { + this.$message({ + message: 'you browser can not work', + type: 'warning' + }) + return false + } + screenfull.toggle() + }, + change() { + this.isFullscreen = screenfull.isFullscreen + }, + init() { + if (screenfull.enabled) { + screenfull.on('change', this.change) + } + }, + destroy() { + if (screenfull.enabled) { + screenfull.off('change', this.change) + } + } + } +} +</script> + +<style scoped> +.screenfull-svg { + display: inline-block; + cursor: pointer; + fill: #5a5e66;; + width: 20px; + height: 20px; + vertical-align: 10px; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Search/foot.vue b/UI source code/dns_mapping_ui-master/src/components/Search/foot.vue new file mode 100644 index 0000000..b34cfd4 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Search/foot.vue @@ -0,0 +1,55 @@ +<template> + <div class="block"> + <el-pagination + :current-page="currentPage4" + :page-sizes="[10, 20, 30, 40]" + :page-size="100" + layout="total, sizes, prev, pager, next, jumper" + :total="400" + @size-change="handleSizeChange" + @current-change="handleCurrentChange" + /> + </div> +</template> + +<script> +export default { + data() { + return { + currentPage1: 5, + currentPage2: 5, + currentPage3: 5, + currentPage4: 4 + } + }, + methods: { + handleSizeChange(val) { + console.log(`每页 ${val} 条`) + }, + handleCurrentChange(val) { + console.log(`当前页: ${val}`) + } + } +} +</script> + +<style lang="scss" scoped> +.block{ + display: flex; + justify-content: flex-end; + float: right; + width: 76%; + height: 50px; + line-height: 50px; + background-color: #fff; +} + .block >>> .el-pagination{ + height: 50px; + line-height: 50px; + padding: 10px 5px; + // align-items: center; + .active{ + color: #4608ad; + } + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Search/input.vue b/UI source code/dns_mapping_ui-master/src/components/Search/input.vue new file mode 100644 index 0000000..e0a30d5 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Search/input.vue @@ -0,0 +1,12 @@ +<template> + <div class="input"> + + </div> +</template> + +<script> +export default {}; +</script> + +<style> +</style>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/components/Search/left.vue b/UI source code/dns_mapping_ui-master/src/components/Search/left.vue new file mode 100644 index 0000000..434299a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Search/left.vue @@ -0,0 +1,100 @@ +<template> + <div class="left"> + <el-collapse v-model="activeNames"> + <el-collapse-item title="端口" name="1"> + <div v-for="(val,key,i) in left.portList" :key="i" class="item"> + <p>{{ val.port }}</p> + <p>{{ val.count }}</p> + </div> + </el-collapse-item> + <el-collapse-item title="地域" name="2"> + <div v-for="(val,key,i) in left.regionList" :key="i" class="item"> + <p>{{ val.province }}</p> + <p>{{ val.count }}</p> + </div> + </el-collapse-item> + <el-collapse-item title="服务类别" name="3"> + <div v-for="(val,key,i) in left.serviceCategoryList" :key="i" class="item"> + <p>{{ val.key }}</p> + <p>{{ val.count }}</p> + </div> + </el-collapse-item> + <el-collapse-item title="运营商" name="4"> + <div v-for="(val,key,i) in left.providerList" :key="i" class="item"> + <p>{{ val.provider }}</p> + <p>{{ val.count }}</p> + </div> + </el-collapse-item> + <el-collapse-item title="服务组件" name="5"> + <div v-for="(val,key,i) in left.componentList" :key="i" class="item"> + <p>{{ val.component }}</p> + <p>{{ val.count }}</p> + </div> + </el-collapse-item> + <el-collapse-item title="漏洞威胁" name="6"> + <div v-for="(val,key,i) in left.vulnerabilityCountList" :key="i" class="item"> + <p>{{ val.vulnerability }}</p> + <p>{{ val.count }}</p> + </div> + </el-collapse-item> + </el-collapse> + </div> +</template> + +<script> +import { mapActions, mapGetters } from 'vuex' +export default { + data() { + return { + activeNames: ['1'] + } + }, + computed: { + ...mapGetters({ + left: 'searchlist/left' + }) + }, + methods: { + ...mapActions({ + leftlistActions: 'searchlist/leftlistActions' + }) + } +} +</script> + +<style lang="scss" scoped> +.left { + width: 22%; + float: left; + // border-radius: 20px; + z-index: 2; + .el-collapse { + border-radius: 20px; + border-top: none; + } + .item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0px 10px; + font-size: 15px; + height: 30px; + + p:nth-of-type(1) { + color: #4608ad; + } + p:nth-of-type(2) { + color: #aca9b3; + } + } +} +.left >>> .el-collapse-item__header { + font-size: 16px; + font-weight: 600; + padding-left: 10px; +} +.left >>> .el-loading-mask{ + z-index: 1 !important; + background-color: white; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/Search/right.vue b/UI source code/dns_mapping_ui-master/src/components/Search/right.vue new file mode 100644 index 0000000..ae109f6 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/Search/right.vue @@ -0,0 +1,116 @@ +<template> + <div class="right bigbox"> + <div class="title"> + <div :class="tabshow == 1 ? 'active' : ''" @click="tab(1)"> + 检索结果 + </div> + <div :class="tabshow == 2 ? 'active' : ''" @click="tab(2)"> + 数据统计 + </div> + <div :class="tabshow == 3 ? 'active' : ''" @click="tab(3)"> + 关联分析 + </div> + <div class="inp"> + <input type="text" placeholder="近一年"> + <el-button type="primary">导出</el-button> + </div> + </div> + + <div class="containerbox"> + <div v-show="tabshow == 1"><Result /></div> + <div v-show="tabshow == 2"><Count /></div> + <div v-show="tabshow == 3"><Relation /></div> + </div> + </div> +</template> + +<script> +import Result from '../SearchList/result.vue' +import Count from '../SearchList/count.vue' +import Relation from '../SearchList/relation.vue' +// import { mapGetters } from 'vuex' +export default { + components: { + Result, + Count, + Relation + }, + data() { + return { + tabshow: 1, + } + }, + // computed:{ + // ...mapGetters({ + // maplist: "searchlist/maplist", + // }) + // }, + created() {}, + methods: { + tab(val) { + this.tabshow = val; + // console.log(val); + var page = document.getElementsByClassName('block')[0]; + if(val == 2 || val == 3){ + page.style.display = "none" + }else{ + page.style.display = "block" + } + }, + + }, + +} +</script> + +<style lang="scss" scoped> +.right { + float: right; + width: 76%; +} +.bigbox .title { + background-color: #fff; + height: 60px; + display: flex; + justify-content: space-between; + align-items: center; +} +.title{ + color: #aca9b3; +// .inp{ +// flex: 1; +// } + div:nth-of-type(1){ + margin-left:10px; + } + div:hover{ + color: #4608ad; + cursor:pointer + } + .inp input{ + height: 32px; + width: 300px; + border:1px solid #aca9b3; + outline-style: none; + border-radius: 5px; + } + .inp button{ + vertical-align: top; + margin-right: 10px; + background-color: #4608ad; + border-color: #4608ad; + } +} +.active { + font-weight: 600; + color: #4608ad !important; + border-bottom:4px solid #4608ad; +} +html,body{ + scroll-behavior:smooth; +} +.right >>> .el-loading-mask{ + z-index: 6 !important; + background-color: white; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/SearchInput/SearchInput.vue b/UI source code/dns_mapping_ui-master/src/components/SearchInput/SearchInput.vue new file mode 100644 index 0000000..60d5d15 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/SearchInput/SearchInput.vue @@ -0,0 +1,552 @@ +<template> + <!-- 父盒子 --> + <div class="father_box"> + <div class="sea_box" @click="onclick"> + <div + v-for="(item, index) in keyword" + :key="index" + class="spanbox" + ref="Tag" + > + <span v-if="Array.isArray(item)" class="tagspan"> + <span v-for="(a, i) in item" :key="i">{{ a[a.length - 1] }}</span> + </span> + <span class="tagspan" v-else>{{ item }}</span> + + <!-- <span class="tagspan" v-if="Array.isArray(item)">{{ item[item.length-1] }}</span> --> + <!-- <span class="tagspan" v-for="(a,i) in item" :key="a" v-if="Array.isArray(item)">{{item[0]}}</span> --> + <i + class="span_close" + @click="removeTag(index, item)" + v-if="index % 2 != 0" + ></i> + </div> + <el-input + placeholder="请输入检索内容" + v-model="currentval" + @keydown.native="handleKeydown" + @focus="searchFoucs" + :style="inputStyle" + class="inputTag" + ref="inputTag" + type="text" + v-if="type === 'input'" + ></el-input> + <el-select + placeholder="请输入检索内容" + v-model="currentval" + @change="addTags" + @keyup.native="handleKeydown" + @focus="searchFoucs" + :style="inputStyle" + class="inputTag" + ref="inputTag" + type="text" + filterable + remote + default-first-option + v-else-if="type == 'select'" + > + <el-option + v-for="item in options" + :key="item.value" + :label="item.label" + :value="item.value" + :disabled="item.disabled" + > + </el-option> + </el-select> + + <el-cascader + :options="options" + :props="{ multiple: true, checkStrictly: true }" + clearable + v-model="currentval" + @change="addTags" + @keyup.native="handleKeydown" + @focus="searchFoucs" + :style="inputStyle" + class="inputTag" + ref="inputTag" + type="text" + filterable + remote + default-first-option + v-else-if="type == 'more'" + ></el-cascader> + + <el-select + placeholder="请输入检索内容" + v-model="currentval" + @change="addTags" + @keyup.native="handleKeydown" + @focus="searchFoucs" + :style="inputStyle" + class="inputTag" + ref="inputTag" + type="text" + filterable + remote + default-first-option + v-else + > + <el-option + v-for="item in options" + :key="item.value" + :label="item.label" + :value="item.value" + :disabled="item.disabled" + > + </el-option> + </el-select> + </div> + </div> +</template> + +<script> +export default { + name: "inputTags", + props: { + parentArr: { + type: Array, + default() { + return ["service", "dns-doh"]; + }, + }, + limit: { + type: Number, + }, + }, + data() { + return { + currentval: "", + keyword: [], + inputLength: "", + // Object: { + // arr: [ + // { + // id: 1, + // name: "service", + // value: "选项1", + // type: "select", + // child: [ + // { + // value: "dns-doh", + // label: "dns-doh", + // }, + // { + // value: "dns-do53", + // label: "dns-do53", + // }, + // ], + // }, + // { + // id: 2, + // name: "ip", + // type: "input", + // }, + // { + // id: 3, + // name: "port", + // type: "input", + // }, + // ], + // }, + options: [], + options1: [ + { + value: "service", + label: "service", + // disabled: false, + }, + { + value: "ip", + label: "ip", + // disabled: false, + }, + { + value: "port", + label: "port", + // disabled: false, + }, + ], + // options2: [ + // { + // value: "dns-doh", + // label: "dns-doh", + // disabled: false, + // }, + // { + // value: "dns-do53", + // label: "dns-do53", + // disabled: false, + // }, + // ], + options2: [ + { + value: "DNS", + label: "DNS", + disabled: false, + children: [ + { + value: "dns-doh", + label: "dns-doh", + disabled: false, + // children: [ + // { + // value: "open-rdns", + // label: "open-rdns", + // disabled: false, + // }, + // { + // value: "egress-rdns", + // label: "egress-rdns", + // disabled: false, + // }, + // { + // value: "forwarder", + // label: "forwarder", + // disabled: false, + // }, + // { + // value: "fwd/rdns", + // label: "fwd/rdns", + // disabled: false, + // }, + // { + // value: "nonstandard", + // label: "nonstandard", + // disabled: false, + // }, + // { + // value: "root", + // label: "root", + // disabled: false, + // }, + // { + // value: "tld", + // label: "tld", + // disabled: false, + // }, + // { + // value: "ns", + // label: "ns", + // disabled: false, + // }, + // ], + }, + { + value: "dns-do53", + label: "dns-do53", + disabled: false, + // children: [ + // { + // value: "proxy", + // label: "proxy", + // disabled: false, + // }, + // { + // value: "server", + // label: "server", + // disabled: false, + // }, + // ], + }, + ], + }, + { + value: "email", + label: "email", + children: [ + { + value: "email-1", + label: "email-1", + }, + { + value: "email-2", + label: "email-2", + }, + ], + }, + ], + isFocus: false, + type: "select", + }; + }, + watch: { + keyword() { + this.$emit("on-change", this.keyword); + }, + currentval(val) { + this.inputLength = this.$refs.inputTag.value.length * 12 + 50; + }, + parentArr() { + this.keyword = this.parentArr.length ? this.parentArr : []; + }, + }, + computed: { + inputStyle() { + let style = {}; + style.width = `${this.inputLength}px`; + return style; + }, + finall() { + return this.keyword.join(","); + }, + }, + mounted() { + this.keyword = this.parentArr; + this.options = this.options1; + // this.edit(); + }, + + // directives:{ + // focus:{ + // inserted:function (e) { + // console.log(e); + // } + // } + // }, + methods: { + removeTag(index, item) { + // console.log(index-1, item); + this.keyword.splice(index, 1); + this.keyword.splice(index - 1, 1); + // this.options1.forEach((item) => { + // item.disabled = false; + // }); + // this.options2.forEach((item) => { + // item.disabled = false; + // }); + }, + addTags() { + // console.log(this.currentval, "code输入"); + // console.log(this.options1, this.options2, "edit"); + if (this.currentval == "service") { + this.options = this.options2; + this.type = "more"; + this.keyword.push(this.currentval); + this.currentval = ""; + } else if (this.currentval == "ip" || this.currentval == "port") { + this.type = "input"; + this.keyword.push(this.currentval); + this.currentval = ""; + } else { + this.options = this.options1; + this.type = "select"; + this.keyword.push(this.currentval); + this.currentval = ""; + } + // for (var i = 0; i < this.keyword.length; i++) { + // console.log(this.keyword[i], 787); + // if (this.keyword[i] == "dns-doh") { + // // console.log(this.options2[this.options2.findIndex((item) => item.value === "dns-doh")].disabled); + // this.options2[ + // this.options2.findIndex((item) => item.value === "dns-doh") + // ].disabled = true; + // } else if (this.keyword[i] == "dns-do53") { + // this.options2[ + // this.options2.findIndex((item) => item.value === "dns-do53") + // ].disabled = true; + // } else if (this.keyword[i] == "ip") { + // // console.log(this.options1[this.options2.findIndex((item) => item.value === "dns-doh")].disabled); + // this.options1[ + // this.options1.findIndex((item) => item.value === "ip") + // ].disabled = true; + // } else if (this.keyword[i] == "port") { + // this.options1[ + // this.options1.findIndex((item) => item.value === "port") + // ].disabled = true; + // } + // } + console.log(this.keyword, "add"); + + // this.edit(); + }, + open() { + this.$alert("输入值不能为空", "提示", { + confirmButtonText: "确定", + }); + }, + handleKeydown(e) { + // console.log(e); + var keyCode = window.event ? e.keyCode : e.which; + this.$nextTick(() => { + if (keyCode === 8) { + // console.log(this.$refs.inputTag.value,'----value'); + // console.log(this.$refs.inputTag.query,'----query'); + // console.log(this.currentval,'cur'); + if ( + this.$refs.inputTag.query === "" || + (this.currentval == "" && this.$refs.inputTag.query == undefined) + ) { + setTimeout(() => { + // console.log(888); + this.keyword.pop(); + this.searchFoucs(); + }); + } + } + if (keyCode == 13) { + if ( + (this.$refs.inputTag && + this.type == "select" && + this.currentval != "") || + this.type == "input" + ) { + console.log(this.$refs.inputTag, this.type, this.currentval); + // this.$refs.inputTag.visible = false; + setTimeout(() => { + this.addTags(); + }); + } + } + }); + }, + onclick() { + this.$nextTick(() => { + // this.$refs.inputTag.focus(); + this.searchFoucs(); + }); + }, + // 输入框键盘删除键删除tag + // deleteTags(state) { + // var keyCode = window.event ? e.keyCode : e.which; + // if (state) { + // setTimeout(() => { + // this.keyword.pop(); + // this.searchFoucs(); + // }); + // } + // }, + // changeArr(arr) { + // var item = {}; + // // arr = arr.toString().split(""); + // for (var i = 0; i < arr.length; i++) { + // var dt = arr[i]; + // if (item[dt]) { + // item[dt]++; + // } else { + // item[dt] = 1; + // } + // } + // return item; + // }, + searchFoucs() { + // console.log(this.keyword,"---keyword"); + var len = this.keyword.length; + var last = this.keyword[len - 1]; + if (last == "service") { + this.options = this.options2; + this.type = "more"; + } else if (last == "ip" || last == "port") { + this.type = "input"; + } else { + this.options = this.options1; + this.type = "select"; + } + }, + // changeInput() { + // // console.log("changeInput"); + // }, + }, +}; +</script> + +<style lang="scss" scoped> +/* 外层div */ +.father_box { + /* width: 300px; */ + box-sizing: border-box; + background-color: white; + border: 1px solid #dcdee2; + border-radius: 4px; + font-size: 12px; + text-align: left; + padding-left: 5px; + word-wrap: break-word; + overflow: hidden; +} +/* 标签 */ +.key, +.value { + display: inline-block; + font-size: 14px; + margin: 3px 4px 3px 0; + background-color: rgb(229, 229, 229); + border: 1px solid #e8eaec; + border-radius: 3px; +} +.spanbox { + display: inline-block; + font-size: 14px; + margin: 3px 4px 3px 0; + background-color: rgb(229, 229, 229); + border: 1px solid #e8eaec; + border-radius: 3px; +} +.tagspan { + height: 24px; + line-height: 22px; + max-width: 100%; + position: relative; + display: inline-block; + padding-left: 8px; + padding-right: 8px; + color: #495060; + font-size: 14px; + cursor: pointer; + opacity: 1; + vertical-align: middle; + overflow: hidden; + transition: 0.25s linear; + color: rgb(26, 26, 26); + font-weight: 600; +} +.span_close { + padding: 0 4px 0 4px; + opacity: 1; + -webkit-filter: none; + filter: none; + color: rgb(26, 26, 26); + font-weight: 600; +} +.span_close:after { + content: "\00D7"; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + /* line-height: 27px; */ + transition: 0.3s, color 0s; +} +/* input */ +.inputTag { + font-size: 16px; + border: none; + box-shadow: none; + outline: none; + background-color: transparent; + padding: 0; + width: auto; + min-width: 250px; + vertical-align: top; + height: 32px; + color: #495060; + line-height: 32px; +} +.el-select--small >>> .el-input--small .el-input__inner { + border: none; +} +.el-select--small >>> .el-input--small .el-input__suffix { + display: none; +} +.el-input--small >>> .el-input__inner { + border: none; +} +.el-cascader >>> .el-input--small .el-input__inner { + border: none; +} +.el-cascader >>> .el-input--small .el-input__suffix { + display: none; +} +</style> +
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/components/SearchList/count.vue b/UI source code/dns_mapping_ui-master/src/components/SearchList/count.vue new file mode 100644 index 0000000..7c95d45 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/SearchList/count.vue @@ -0,0 +1,502 @@ +<template> + <div class="count"> + <ul class="count_list"> + <!-- 时间轴 --> + <li> + <Time /> + </li> + <!-- DNS-DoH世界分布 --> + <li> + <div class="nav"> + <p>DoH世界分布</p> + </div> + <div class="charts"> + <!-- 右侧图表 --> + <div class="DOHSJ"> + <DOHSJ + v-if="maplist.dohWorldMapDataList != undefined" + :dohsj="maplist.dohWorldMapDataList" + /> + </div> + <div class="solid"> + <ul> + <!-- 左侧排序 --> + <li + v-for="(item, index) in demolist(maplist.dohWorldMapDataList,8)" + :key="index" + > + <div class="first_column">{{ item.country }}</div> + <div class="second_column"> + <el-progress + id="text" + :percentage="getPercentage(item.count,maplist.dohWorldMapDataList[0].count)" + :stroke-width="12" + /> + </div> + <div class="third_column">{{ item.count }}</div> + </li> + </ul> + </div> + </div> + </li> + <!-- DoH中国分布 --> + <li> + <div class="nav"> + <p>DoH中国分布</p> + </div> + <div class="charts"> + <!-- 左侧图表 --> + <div class="DOHSJ"> + <DOHZG + v-if="maplist.dohChinaMapList != undefined" + :dohzg="maplist.dohChinaMapList" + /> + </div> + <!-- 右侧排序 --> + <div class="solid"> + <ul> + <li + v-for="(item, index) in demolist(maplist.dohChinaMapList, 8)" + :key="index" + > + <div class="first_column">{{ item.province }}</div> + <div class="second_column"> + <el-progress + id="text" + :percentage=" + getPercentage( + item.count, + maplist.dohChinaMapList[0].count + ) + " + :stroke-width="12" + /> + </div> + <div class="third_column">{{ item.count }}</div> + <br> + </li> + </ul> + </div> + </div> + </li> + <!-- DNS-Do53世界分布 --> + <li> + <div class="nav"> + <p>DNS-Do53世界分布</p> + </div> + <div class="charts"> + <div class="DOHSJ"> + <DO53SJ + v-if="maplist.do53WorldMapDataList != undefined" + :do53sj="maplist.do53WorldMapDataList" + /> + </div> + <div class="solid"> + <ul> + <li + v-for="(item, id) in demolist(maplist.do53WorldMapDataList, 8)" + :key="id" + > + <div class="first_column">{{ item.country }}</div> + <div class="second_column"> + <el-progress + id="text" + :percentage=" + getPercentage( + item.count, + maplist.do53WorldMapDataList[0].count + ) + " + :stroke-width="12" + /> + </div> + <div class="third_column">{{ item.count }}</div> + </li> + </ul> + </div> + </div> + </li> + <!-- DNS-Do53中国分布 --> + <li> + <div class="nav"> + <p>Do53中国分布</p> + </div> + <div class="charts"> + <!-- 左侧图表 --> + <div class="DOHSJ"> + <DO53ZG + v-if="maplist.do53ChinaMapList != undefined" + :do53zg="maplist.do53ChinaMapList" + /> + </div> + <!-- 右侧排序 --> + <div class="solid"> + <ul> + <li + v-for="(item, id) in demolist(maplist.do53ChinaMapList, 8)" + :key="id" + > + <div class="first_column">{{ item.province }}</div> + <div class="second_column"> + <el-progress + id="text" + :percentage=" + getPercentage( + item.count, + maplist.do53ChinaMapList[0].count + ) + " + :stroke-width="12" + /> + </div> + <div class="third_column">{{ item.count }}</div> + </li> + </ul> + </div> + </div> + </li> + <!-- Do53Forwarder世界分布 --> + <li> + <div class="nav"> + <p>Do53Forwarder世界分布</p> + </div> + <div class="charts"> + <!-- 右侧图表 --> + <div class="DOHSJ"> + <Do53Forwarder + v-if="maplist.do53ForwarderList != undefined" + :do53forwarder="maplist.do53ForwarderList" + /> + </div> + <div class="solid"> + <ul> + <!-- 左侧排序 --> + <li + v-for="(item, id) in demolist(maplist.do53ForwarderList, 8)" + :key="id" + > + <div class="first_column">{{ item.country }}</div> + <div class="second_column"> + <el-progress + id="text" + :percentage=" + getPercentage( + item.count, + maplist.do53ForwarderList[0].count + ) + " + :stroke-width="12" + /> + </div> + <div class="third_column">{{ item.count }}</div> + </li> + </ul> + </div> + </div> + </li> + <!-- egress-dns世界分布 --> + <li> + <div class="nav"> + <p>egress-dns世界分布</p> + </div> + <div class="charts"> + <!-- 右侧图表 --> + <div class="DOHSJ"> + <Do53Egressdns + v-if="maplist.do53EgressDnsList != undefined" + :do53egressdns="maplist.do53EgressDnsList" + /> + </div> + <div class="solid"> + <ul> + <!-- 左侧排序 --> + <li + v-for="(item, id) in demolist(maplist.do53EgressDnsList, 8)" + :key="id" + > + <div class="first_column">{{ item.country }}</div> + <div class="second_column"> + <el-progress + id="text" + :percentage=" + getPercentage( + item.count, + maplist.do53EgressDnsList[0].count + ) + " + :stroke-width="12" + /> + </div> + <div class="third_column">{{ item.count }}</div> + </li> + </ul> + </div> + </div> + </li> + <!-- fwd/rdns世界分布 --> + <li> + <div class="nav"> + <p>fwd/rdns世界分布</p> + </div> + <div class="charts"> + <!-- 右侧图表 --> + <div class="DOHSJ"> + <Do53Fwdrdns + v-if="maplist.do53FwdRdnsList != undefined" + :do53fwdrdns="maplist.do53FwdRdnsList" + /> + </div> + <div class="solid"> + <ul> + <!-- 左侧排序 --> + <li + v-for="(item, id) in demolist(maplist.do53FwdRdnsList, 8)" + :key="id" + > + <div class="first_column">{{ item.country }}</div> + <div class="second_column"> + <el-progress + id="text" + :percentage=" + getPercentage( + item.count, + maplist.do53FwdRdnsList[0].count + ) + " + :stroke-width="12" + /> + </div> + <div class="third_column">{{ item.count }}</div> + </li> + </ul> + </div> + </div> + </li> + <!-- open-rdns世界分布 --> + <li> + <div class="nav"> + <p>open-rdns世界分布</p> + </div> + <div class="charts"> + <!-- 右侧图表 --> + <div class="DOHSJ"> + <Do53Opendns + v-if="maplist.do53OpenRdnsList != undefined" + :do53opendns="maplist.do53OpenRdnsList" + /> + </div> + <div class="solid"> + <ul> + <!-- 左侧排序 --> + <li + v-for="(item, id) in demolist(maplist.do53OpenRdnsList, 8)" + :key="id" + > + <div class="first_column">{{ item.country }}</div> + <div class="second_column"> + <el-progress + id="text" + :percentage=" + getPercentage( + item.count, + maplist.do53OpenRdnsList[0].count + ) + " + :stroke-width="12" + /> + </div> + <div class="third_column">{{ item.count }}</div> + </li> + </ul> + </div> + </div> + </li> + <!-- nonstandard世界分布 --> + <li> + <div class="nav"> + <p>nonstandard世界分布</p> + </div> + <div class="charts"> + <!-- 右侧图表 --> + <div class="DOHSJ"> + <Do53Nonstandard + v-if="maplist.do53NonstandardList != undefined" + :do53nonstandard="maplist.do53NonstandardList" + /> + </div> + <div class="solid"> + <ul> + <!-- 左侧排序 --> + <li + v-for="(item, id) in demolist(maplist.do53NonstandardList, 8)" + :key="id" + > + <div class="first_column">{{ item.country }}</div> + <div class="second_column"> + <el-progress + id="text" + :percentage=" + getPercentage( + item.count, + maplist.do53NonstandardList[0].count + ) + " + :stroke-width="12" + /> + </div> + <div class="third_column">{{ item.count }}</div> + </li> + </ul> + </div> + </div> + </li> + </ul> + </div> +</template> + +<script> +import Time from '../../components/Echarts/Time.vue' +import DOHSJ from '../../components/Echarts/Dohsj.vue' +import DOHZG from '../../components/Echarts/Dohzg.vue' +import DO53SJ from '../../components/Echarts/Do53sj.vue' +import DO53ZG from '../../components/Echarts/Do53zg.vue' +import Do53Forwarder from '../../components/Echarts/Do53Forwarder.vue' +import Do53Egressdns from '../../components/Echarts/Do53Egressdns.vue' +import Do53Fwdrdns from '../../components/Echarts/Do53Fwdrdns.vue' +import Do53Opendns from '../../components/Echarts/Do53Openrdns.vue' +import Do53Nonstandard from '../../components/Echarts/Do53Nonstandard.vue' +import { mapActions, mapGetters } from 'vuex' +export default { + components: { + Time, + DOHSJ, + DOHZG, + DO53SJ, + DO53ZG, + Do53Forwarder, + Do53Egressdns, + Do53Fwdrdns, + Do53Opendns, + Do53Nonstandard + }, + data() { + return {} + }, + computed: { + ...mapGetters({ + maplist: 'searchlist/maplist' + }) + }, + // created(){ + // this.cmap() + // }, + + methods: { + ...mapActions({ + maplistActions: 'searchlist/maplistActions' + }), + demolist(data, number) { + if (data != undefined) { + var newData = data.filter((item, i) => { + return i < number + }) + return newData + } + }, + getPercentage(value, maxValue) { + return (value / this.ceilNumber(maxValue)) * 100 + }, + ceilNumber(number) { + let bite = 0 + if (number < 10) { + return 10 + } + if (number < 100) { + return Math.ceil(number) * Math.pow(10, 1) + } + while (number >= 100) { + number /= 10 + bite += 1 + } + return Math.ceil(number) * Math.pow(10, bite) + } + }, + mounted() { + this.maplistActions() + } +} +</script> + +<style lang="scss" scoped> +.count { + width: 100%; + .count_list { + width: 100%; + padding: 0; + margin: 0; + li { + width: 100%; + list-style: none; + .nav { + width: 100%; + background-color: white; + border-bottom: 1px solid #dcdcdc; + height: 50px; + line-height: 50px; + padding: 0px 20px; + font-weight: bolder; + } + .charts { + background-color: white; + display: flex; + // width: 100%; + justify-content: space-evenly; + align-items: center; + .DOHSJ { + width: 500px; + height: 300px; + } + .solid { + width: 50%; + } + .solid ul { + padding-left: 0px; + } + .solid ul li { + // width:50%; + // background-color: yellow; + line-height: 30px; + display: flex; + justify-content: flex-end; + align-items: center; + .first_column { + padding-right: 10px; + } + .second_column { + width: 360px; + } + @media only screen and (min-width: 768px) and (max-width: 1370px) { + .second_column { + width: 320px; + } + } + // @media only screen and (min-width: 1371px) and (max-width: 2400px) { + // .dashboard-container .text >>> .massage { + // width: 63%; + // } + // } + } + } + } + } +} +#text >>> .el-progress-bar { + width: 360px !important; + .el-progress-bar__inner { + background-color: #4608ad; + } +} +#text >>> .el-progress__text { + display: none !important; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/SearchList/relation.vue b/UI source code/dns_mapping_ui-master/src/components/SearchList/relation.vue new file mode 100644 index 0000000..0510504 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/SearchList/relation.vue @@ -0,0 +1,56 @@ +<template> + <div class="relation"> + <title>数据统计分析工具</title> + <div class="tip"> + <p>类型统计</p> + <p>|</p> + <p>总计<span> 0 </span>类</p> + </div> + <div class="content"> + <el-empty description="暂无数据"></el-empty> + </div> + </div> +</template> + +<script> +export default {} +</script> + +<style lang="scss" scoped> +.relation { + width: 100%; + font-weight: 600; + + title { + display: block; + height: 45px; + line-height: 45px; + margin-top: 12px; + padding-left: 12px; + background-color: #fff; + } + .tip { + display: flex; + align-items: center; + justify-content: flex-start; + height: 45px; + line-height: 45px; + margin-top: 12px; + padding-left: 12px; + p:nth-of-type(2) { + margin: 0px 10px; + color: #ccc; + } + span { + color: #4608ad; + } + } + // .content{ + // height: 500px; + // line-height: 500px; + // text-align: center; + // color: #ccc; + // background-color: #fff; + // } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/SearchList/result.vue b/UI source code/dns_mapping_ui-master/src/components/SearchList/result.vue new file mode 100644 index 0000000..049893c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/SearchList/result.vue @@ -0,0 +1,472 @@ +<template> + <div class="result"> + <div class="box"> + <ul> + <li v-for="(item1, index1) in list.list" :key="index1" class="item"> + <!-- 详情的标题 --> + <div class="title"> + <div class="title_left"> + <span>{{ item1.ip }}</span> + <span>{{ + item1.ipInformation ? item1.ipInformation.country : "" + }}</span> + <span>{{ + item1.ipInformation ? item1.ipInformation.province : "" + }}</span> + <span>{{ + item1.ipInformation ? item1.ipInformation.city : "" + }}</span> + </div> + <div class="title_right"> + <i class="el-icon-time" /><span>{{ item1.timestamp }}</span> + </div> + </div> + <!-- 详情的内容 --> + <div class="content"> + <!-- 详情左侧 --> + <div class="content_left"> + <!-- 左侧头部标签 --> + <div class="tag"> + <div class="tag_left"> + <p>漏洞威胁</p> + </div> + <div class="tag_right"> + <span><i class="el-icon-receiving" />{{ item1.protocolType }}</span> + <span><i class="el-icon-film" />{{ item1.ipType }}</span> + </div> + </div> + <!-- 左侧链接接内容 --> + <div class="link"> + <i class="el-icon-thumb" /> + <p>{{ item1.statusCode }}</p> + </div> + <!-- 左侧列表内容 --> + <div class="content_list"> + <div class="list_left"> + <div class="text"> + <p>自治域编号</p> + <p + :title="`${ + item1.ipInformation + ? item1.ipInformation.asnumber + ? item1.ipInformation.asnumber + : '' + : '' + }`" + > + {{ + item1.ipInformation + ? item1.ipInformation.asnumber + ? item1.ipInformation.asnumber + : "--" + : "--" + }} + </p> + </div> + <div class="text"> + <p>自治域</p> + <p>--</p> + </div> + <div class="text"> + <p>运营商</p> + <p + :title="`${ + item1.ipInformation + ? item1.ipInformation.provider + ? item1.ipInformation.provider + : '' + : '' + }`" + > + {{ + item1.ipInformation + ? item1.ipInformation.provider + ? item1.ipInformation.provider + : "--" + : "--" + }} + </p> + </div> + <div class="text"> + <p> IP归属</p> + <p + :title="`${ + item1.ipInformation + ? item1.ipInformation.isp + ? item1.ipInformation.isp + : '' + : '' + }`" + > + {{ + item1.ipInformation + ? item1.ipInformation.isp + ? item1.ipInformation.isp + : "--" + : "--" + }} + </p> + </div> + </div> + <div class="list_right"> + <div class="text"> + <p>服务组件</p> + <select + v-if="item1.componentList && item1.componentList.length != 0" + id="" + name="" + > + <option + v-for="(a, index) in item1.componentList" + :key="index" + value="" + > + {{ a }} + </option> + </select> + <p v-else>--</p> + </div> + <div class="text"> + <p>访问路径</p> + <!-- <select v-if="item1.pathList.length != 0" id="" name=""> --> + <select v-if="item1.pathList ? item1.pathList.length : ''" id="" name=""> + <option + v-for="(b, index) in item1.pathList" + :key="index" + value="" + :title="`${b}`" + >{{ b }} + </option> + </select> + <p v-else>--</p> + </div> + <div class="text"> + <p>主机名</p> + <p :title="`${item1.host}`"> + {{ item1.host ? item1.host : "--" }} + </p> + </div> + <div class="text"> + <p>服务类别</p> + <!-- <p>DNS,DNS-DoH,转发服务器</p> --> + <!-- <div class="tag"> --> + <div class="tag_left"> + <el-tag + v-for="(c, index) in item1.tags" + :key="index" + :title="`${c}`" + > + {{ c }} + </el-tag> + </div> + <!-- </div> --> + </div> + </div> + </div> + <!-- 底部小框 --> + <div class="content_bottom"> + <i class="el-icon-data-analysis" /> + <p v-for="(d, index) in item1.ipCert" :key="index" :title="`${d.ca}`"> + {{ d.ca }} + </p> + </div> + </div> + <!-- 详情右侧 --> + <div class="content_right"> + <result-tab :tab-data="item1" /> + </div> + </div> + </li> + </ul> + </div> + </div> +</template> + +<script> +import { mapActions, mapGetters } from 'vuex' +import resultTab from './resultTab.vue' +// import { Tab } from "./xxk"; +// import indexVue from "../Breadcrumb/index.vue"; + +export default { + components: { resultTab }, + data() { + return {} + }, + created() {}, + computed: { + ...mapGetters({ + list: 'searchlist/list' + }) + }, + methods: { + ...mapActions({ + listAction: 'searchlist/listActions' + }) + }, + mounted() {} +} +</script> + +<style lang="scss" scoped> +.box { + ul { + padding: 0px; + margin: 10px 0px; + li { + list-style: none; + background-color: #fff; + margin-bottom: 15px; + } + } + .item { + // width: 100%; + .title { + // width: 50%; + display: flex; + justify-content: space-between; + align-items: center; + background-color: white; + padding: 0px 20px; + height: 50px; + border-bottom: 1px solid #dcdcdc; + margin: 0px; + .title_left span:nth-of-type(1) { + font-size: 20px; + color: #4608ad; + } + .title_left span:nth-of-type(2), + span:nth-of-type(3), + span:nth-of-type(4) { + color: #aca9b3; + padding-left: 13px; + font-size: 15px; + } + } + .content { + width: 100%; + // width: 566px; + display: flex; + .content_left { + width: 50%; + border-right: 1px solid #dcdcdc; + // 左侧标签 + .tag { + height: 50px; + // background-color: palevioletred; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0px 20px; + p { + display: inline-block; + height: 30px; + width: 72px; + line-height: 30px; + text-align: center; + border-radius: 7px; + font-size: 13px; + } + p:nth-of-type(1) { + background-color: #d9e4ff; + color: #4608ad; + } + // p:nth-of-type(2) { + // background-color: #eef7fc; + // color: #5abee7; + // } + } + // 左侧链接 + .link { + width: 95%; + height: 30px; + margin: 10px auto; + background-color: #d9e4ff; + border-radius: 16px; + position: relative; + .el-icon-thumb { + display: inline-block; + border-radius: 50%; + background-color: #4608ad; + color: #fff; + width: 25px; + height: 25px; + line-height: 25px; + text-align: center; + position: absolute; + left: 10px; + top: 3px; + } + p { + // margin-left: 35px; + line-height: 30px; + margin: 0px 40px; + } + } + // 左侧列表内容 + .content_list { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin: 10px 0px; + .list_right { + border-left: 1px solid #dcdcdc; + } + .list_left, + .list_right { + width: 50%; + .text { + display: flex; + justify-content: space-between; + align-items: center; + // width: 283px; + // background-color: #ff0; + padding: 0px 20px; + font-size: 15px; + select { + border: 0px; + outline-style: none; + margin-right: 50px; + } + @media only screen and (min-width: 768px) and (max-width: 1370px) { + select { + margin-right: 10px; + width: 50%; + } + } + @media only screen and (min-width: 1371px) and (max-width: 2048px) { + select { + margin-right: 15px; + width: 50%; + white-space: nowrap; + text-overflow: ellipsis; + } + } + p { + line-height: 30px; + margin: 0px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + cursor: pointer; + width: 50%; + } + .tag_left { + display: flex; + width: 50%; + flex-wrap: wrap; + cursor: pointer; + .el-tag--small { + background-color: #d9e4ff; + color: #4608ad; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + width: 65px; + margin-right: 3px; + } + @media only screen and (min-width: 768px) and (max-width: 1370px) { + .el-tag--small { + width: 45px; + } + } + @media only screen and (min-width: 1371px) and (max-width: 2048px) { + .el-tag--small { + width: 50px; + } + } + // flex-direction: column !important; + // p { + // display: inline-block; + // height: 30px; + // width: 67px !important; + // line-height: 30px; + // text-align: center; + // border-radius: 7px; + // font-size: 13px; + // margin-bottom: 3px; + // margin-right: 3px; + // } + } + p:nth-of-type(2) { + // flex: 1; + // -webkit-box-flex: 1; + width: 50%; + text-align: center; + // width: 90px; + } + } + } + } + } + // 右侧列表 + .content_right { + // display: flex; + width: 50%; + } + } + } +} + +.el-tabs__content >>> .el-tab-pane #text { + width: 100% !important; + resize: none; + outline: none; + border: none; + background-color: #f9fafb; + color: #aca9b3; + font-size: 16px; +} +.content_bottom { + display: flex; + align-items: center; + padding-left: 20px; + height: 30px; + line-height: 30px; + margin: 10px 0px; + width: 93%; + // width: auto; + // border: 1px solid transparent; + // border-radius:7px ; + .el-icon-data-analysis { + display: inline-block; + border-radius: 10px 0px 0px 10px; + background-color: #4608ad; + color: white; + display: inline-block; + height: 30px; + line-height: 30px; + width: 30px; + text-align: center; + } + P { + padding: 0px 7px; + display: inline-block; + background-color: #d9e4ff; + font-size: 15px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + cursor: pointer; + } + p:last-child { + border-left: 1px solid #cbc8c8; + border-radius: 0px 10px 10px 0px; + } +} +.tab input { + background: #f6f3f3; + border: 1px solid #ff0000; +} +.tab .active { + background: #e9d4d4; +} +.tab div { + width: 300px; + height: 250px; + display: none; + padding: 10px; + background: #e9d4d4; + border: 1px solid #ff0000; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/SearchList/resultTab.vue b/UI source code/dns_mapping_ui-master/src/components/SearchList/resultTab.vue new file mode 100644 index 0000000..6e358b3 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/SearchList/resultTab.vue @@ -0,0 +1,182 @@ +<template> + <!-- 详情右侧 --> + <el-tabs v-model="activeName" @tab-click="handleClick"> + <el-tab-pane label="响应" name="a1"> + <div class="contentright_box"> + <div> + <textarea + id="" + v-model="xylist" + readonly + name="" + cols="30" + rows="10" + /> + </div> + </div> + </el-tab-pane> + <el-tab-pane label="证书" name="a2"> + <div class="contentright_box"> + <div> + <textarea + id="" + v-model="zslist" + readonly + name="" + cols="30" + rows="10" + /> + </div> + </div> + </el-tab-pane> + <el-tab-pane label="http" name="a3"> + <div class="contentright_box"> + <div> + <textarea id="" v-model="httplist" name="" cols="30" rows="10" /> + </div> + </div> + </el-tab-pane> + </el-tabs> +</template> + +<script> +export default { + props: { tabData: {}}, + data() { + return { + // first: 1, + // second: 2, + // third: 3, + activeName: 'a1' + } + }, + computed: { + // 处理证书展示 + zslist: function() { + let zslist1 = '' + // console.log(this.tabData.ipCert); + if (this.tabData.ipCert == undefined || this.tabData.ipCert == null) { + return zslist1 + } else { + if (this.tabData.ipCert.length >= 1) { + this.tabData.ipCert.map((item, index) => { + // console.log(item, index, 999); + zslist1 += `${item.certificate}\n-----------------------\n` + }) + return zslist1 + } + } + }, + // banner 响应区 + xylist: function() { + let xylist1 = '' + // doh 设置展示数据格式 + if (this.tabData.banner && this.tabData.dnsType == undefined) { + if (this.tabData.banner.length >= 1) { + this.tabData.banner.map((item, index) => { + // console.log(item,"length"); + xylist1 += `${item}\n----------------------\n` + }) + return xylist1 + } + } else if (this.tabData.banner === undefined) { + return xylist1 + } else if (this.tabData.dnsType == 5) { + console.log(555); + if (this.tabData.banner.length >= 1) { + this.tabData.banner.map((item, index) => { + console.log(item); + if(index===0){ + xylist1 += `${item}\n----------------------\n` + }else{ + xylist1 +=`record=${item.record}\n----------------------\n` + } + // else{ + // xylist1 =`record=${this.tabData.record}` + // } + }) + } + return xylist1 + // return `record=${this.tabData.record}` + } else if (this.tabData.dnsType === 3 || this.tabData.dnsType === 2) { + if (this.tabData.banner.length >= 1) { + this.tabData.banner.map((item, index) => { + if(index===0){ + xylist1 += `${item}\n--------------------\n` + }else{ + xylist1 += JSON.stringify(item)+`\n--------------------\n` + // xylist1 += + // `服务器ip地址:${item.city}\n` + + // `IP所属国家:${item.country}\n` + + // `IP所属省份:${item.province}\n` + + // `IP所属城市:${item.city}\n` + + // `IP所属区县:${item.district}\n` + + // `IP所属提供服务商:${item.provider}\n` + + // `IP所属运行商:${item.isp}\n` + + // `自治域编码:${item.asnumber}\n----------------\n`; + + } + // console.log(item,"length"); + // this.xylist += JSON.stringify(item)+'\n' + + }) + return xylist1 + } else { + return this.tabData.banner[0] + } + } else { + xylist1 = this.tabData.banner[0] + } + return xylist1 + }, + // http页签展示处理 + httplist: function() { + // 数据格式和接口返回值暂时版 + let httpHearders = '' + if (this.tabData.httpContent === undefined || this.tabData.httpContent === null) { + return httpHearders + } else { + this.tabData.httpContent.map((item, index) => { + // console.log(item,"length"); + httpHearders += `${item}\n-------------------------------\n` + }) + return httpHearders + } + return httpHearders + } + }, + created() {}, + methods: { + handleClick(tab, event) { + // console.log(tab, event); + } + } +} +</script> + +<style lang="scss" scoped> +textarea { + width: 100%; + resize: none; + outline: none; + border: none; + background-color: #f9fafb; + color: #aca9b3; + font-size: 16px; +} + +</style> +<style> +.el-tabs__nav-scroll { + padding-left: 12px; +} +.el-tabs__nav-scroll .is-active { + color: #4608ad !important; +} +.el-tabs__active-bar { + background-color: #4608ad !important; +} +.el-tabs__nav :hover{ + color: #4608ad !important; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/SizeSelect/index.vue b/UI source code/dns_mapping_ui-master/src/components/SizeSelect/index.vue new file mode 100644 index 0000000..e490dce --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/SizeSelect/index.vue @@ -0,0 +1,57 @@ +<template> + <el-dropdown trigger="click" @command="handleSetSize"> + <div> + <svg-icon class-name="size-icon" icon-class="size" /> + </div> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value"> + {{ + item.label }} + </el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> +</template> + +<script> +export default { + data() { + return { + sizeOptions: [ + { label: 'Default', value: 'default' }, + { label: 'Medium', value: 'medium' }, + { label: 'Small', value: 'small' }, + { label: 'Mini', value: 'mini' } + ] + } + }, + computed: { + size() { + return this.$store.getters.size + } + }, + methods: { + handleSetSize(size) { + this.$ELEMENT.size = size + this.$store.dispatch('app/setSize', size) + this.refreshView() + this.$message({ + message: '布局设置成功', + type: 'success' + }) + }, + refreshView() { + // In order to make the cached page re-rendered + this.$store.dispatch('tagsView/delAllCachedViews', this.$route) + + const { fullPath } = this.$route + + this.$nextTick(() => { + this.$router.replace({ + path: '/redirect' + fullPath + }) + }) + } + } + +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/components/SvgIcon/index.vue b/UI source code/dns_mapping_ui-master/src/components/SvgIcon/index.vue new file mode 100644 index 0000000..9a3318e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/SvgIcon/index.vue @@ -0,0 +1,62 @@ +<template> + <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" /> + <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners"> + <use :href="iconName" /> + </svg> +</template> + +<script> +// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage +import { isExternal } from '@/utils/validate' + +export default { + name: 'SvgIcon', + props: { + iconClass: { + type: String, + required: true + }, + className: { + type: String, + default: '' + } + }, + computed: { + isExternal() { + return isExternal(this.iconClass) + }, + iconName() { + return `#icon-${this.iconClass}` + }, + svgClass() { + if (this.className) { + return 'svg-icon ' + this.className + } else { + return 'svg-icon' + } + }, + styleExternalIcon() { + return { + mask: `url(${this.iconClass}) no-repeat 50% 50%`, + '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%` + } + } + } +} +</script> + +<style scoped> +.svg-icon { + width: 1em; + height: 1em; + vertical-align: -0.15em; + fill: currentColor; + overflow: hidden; +} + +.svg-external-icon { + background-color: currentColor; + mask-size: cover!important; + display: inline-block; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/ThemePicker/index.vue b/UI source code/dns_mapping_ui-master/src/components/ThemePicker/index.vue new file mode 100644 index 0000000..2fc497b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/ThemePicker/index.vue @@ -0,0 +1,165 @@ +<template> + <el-color-picker + v-model="theme" + :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d']" + class="theme-picker" + popper-class="theme-picker-dropdown" + /> +</template> + +<script> +const version = require('element-ui/package.json').version // element-ui version from node_modules +const ORIGINAL_THEME = '#409EFF' // default color +import Cookies from 'js-cookie' +export default { + data() { + return { + chalk: '', // content of theme-chalk css + theme: '' + } + }, + computed: { + defaultTheme() { + return this.$store.state.settings.theme + } + }, + watch: { + defaultTheme: { + handler: function(val, oldVal) { + this.theme = val + }, + immediate: true + }, + async theme(val) { + Cookies.set('theme', val, { expires: 365 }) + const oldVal = this.chalk ? this.theme : Cookies.get('theme') ? Cookies.get('theme') : ORIGINAL_THEME + if (typeof val !== 'string') return + const themeCluster = this.getThemeCluster(val.replace('#', '')) + const originalCluster = this.getThemeCluster(oldVal.replace('#', '')) + + const getHandler = (variable, id) => { + return () => { + const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', '')) + const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster) + + let styleTag = document.getElementById(id) + if (!styleTag) { + styleTag = document.createElement('style') + styleTag.setAttribute('id', id) + document.head.appendChild(styleTag) + } + styleTag.innerText = newStyle + } + } + + if (!this.chalk) { + const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css` + await this.getCSSString(url, 'chalk') + } + + const chalkHandler = getHandler('chalk', 'chalk-style') + + chalkHandler() + + const styles = [].slice.call(document.querySelectorAll('style')) + .filter(style => { + const text = style.innerText + return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text) + }) + styles.forEach(style => { + const { innerText } = style + if (typeof innerText !== 'string') return + style.innerText = this.updateStyle(innerText, originalCluster, themeCluster) + }) + + this.$emit('change', val) + } + }, + + methods: { + updateStyle(style, oldCluster, newCluster) { + let newStyle = style + oldCluster.forEach((color, index) => { + newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index]) + }) + return newStyle + }, + + getCSSString(url, variable) { + return new Promise(resolve => { + const xhr = new XMLHttpRequest() + xhr.onreadystatechange = () => { + if (xhr.readyState === 4 && xhr.status === 200) { + this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '') + resolve() + } + } + xhr.open('GET', url) + xhr.send() + }) + }, + + getThemeCluster(theme) { + const tintColor = (color, tint) => { + let red = parseInt(color.slice(0, 2), 16) + let green = parseInt(color.slice(2, 4), 16) + let blue = parseInt(color.slice(4, 6), 16) + + if (tint === 0) { // when primary color is in its rgb space + return [red, green, blue].join(',') + } else { + red += Math.round(tint * (255 - red)) + green += Math.round(tint * (255 - green)) + blue += Math.round(tint * (255 - blue)) + + red = red.toString(16) + green = green.toString(16) + blue = blue.toString(16) + + return `#${red}${green}${blue}` + } + } + + const shadeColor = (color, shade) => { + let red = parseInt(color.slice(0, 2), 16) + let green = parseInt(color.slice(2, 4), 16) + let blue = parseInt(color.slice(4, 6), 16) + + red = Math.round((1 - shade) * red) + green = Math.round((1 - shade) * green) + blue = Math.round((1 - shade) * blue) + + red = red.toString(16) + green = green.toString(16) + blue = blue.toString(16) + + return `#${red}${green}${blue}` + } + + const clusters = [theme] + for (let i = 0; i <= 9; i++) { + clusters.push(tintColor(theme, Number((i / 10).toFixed(2)))) + } + clusters.push(shadeColor(theme, 0.1)) + return clusters + } + } +} +</script> + +<style> +.theme-message, +.theme-picker-dropdown { + z-index: 99999 !important; +} + +.theme-picker .el-color-picker__trigger { + height: 26px !important; + width: 26px !important; + padding: 2px; +} + +.theme-picker-dropdown .el-color-dropdown__link-btn { + display: none; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/UploadExcel/index.vue b/UI source code/dns_mapping_ui-master/src/components/UploadExcel/index.vue new file mode 100644 index 0000000..a78f966 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/UploadExcel/index.vue @@ -0,0 +1,138 @@ +<template> + <div> + <input ref="excel-upload-input" class="excel-upload-input" type="file" accept=".xlsx, .xls" @change="handleClick"> + <div class="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover"> + 拖拽excel文件到此处 或者 + <el-button :loading="loading" style="margin-left:16px;" size="mini" type="primary" @click="handleUpload"> + 浏览 + </el-button> + </div> + </div> +</template> + +<script> +import XLSX from 'xlsx' + +export default { + props: { + beforeUpload: Function, // eslint-disable-line + onSuccess: Function// eslint-disable-line + }, + data() { + return { + loading: false, + excelData: { + header: null, + results: null + } + } + }, + methods: { + generateData({ header, results }) { + this.excelData.header = header + this.excelData.results = results + this.onSuccess && this.onSuccess(this.excelData) + }, + handleDrop(e) { + e.stopPropagation() + e.preventDefault() + if (this.loading) return + const files = e.dataTransfer.files + if (files.length !== 1) { + this.$message.error('只支持单个文件上传!') + return + } + const rawFile = files[0] + + if (!this.isExcel(rawFile)) { + this.$message.error('只支持.xlsx, .xls, .csv 格式文件') + return false + } + this.upload(rawFile) + e.stopPropagation() + e.preventDefault() + }, + handleDragover(e) { + e.stopPropagation() + e.preventDefault() + e.dataTransfer.dropEffect = 'copy' + }, + handleUpload() { + this.$refs['excel-upload-input'].click() + }, + handleClick(e) { + const files = e.target.files + const rawFile = files[0] // only use files[0] + if (!rawFile) return + this.upload(rawFile) + }, + upload(rawFile) { + this.$refs['excel-upload-input'].value = null // fix can't select the same excel + + if (!this.beforeUpload) { + this.readerData(rawFile) + return + } + const before = this.beforeUpload(rawFile) + if (before) { + this.readerData(rawFile) + } + }, + readerData(rawFile) { + this.loading = true + return new Promise((resolve, reject) => { + const reader = new FileReader() + reader.onload = e => { + const data = e.target.result + const workbook = XLSX.read(data, { type: 'array' }) + const firstSheetName = workbook.SheetNames[0] + const worksheet = workbook.Sheets[firstSheetName] + const header = this.getHeaderRow(worksheet) + const results = XLSX.utils.sheet_to_json(worksheet) + this.generateData({ header, results }) + this.loading = false + resolve() + } + reader.readAsArrayBuffer(rawFile) + }) + }, + getHeaderRow(sheet) { + const headers = [] + const range = XLSX.utils.decode_range(sheet['!ref']) + let C + const R = range.s.r + /* start in the first row */ + for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */ + const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] + /* find the cell in the first row */ + let hdr = 'UNKNOWN ' + C // <-- replace with your desired default + if (cell && cell.t) hdr = XLSX.utils.format_cell(cell) + headers.push(hdr) + } + return headers + }, + isExcel(file) { + return /\.(xlsx|xls|csv)$/.test(file.name) + } + } +} +</script> + +<style scoped> +.excel-upload-input{ + display: none; + z-index: -9999; +} +.drop{ + border: 2px dashed #bbb; + width: 600px; + height: 160px; + line-height: 160px; + margin: 0 auto; + font-size: 24px; + border-radius: 5px; + text-align: center; + color: #bbb; + position: relative; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/components/YamlEdit/index.vue b/UI source code/dns_mapping_ui-master/src/components/YamlEdit/index.vue new file mode 100644 index 0000000..83778f4 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/components/YamlEdit/index.vue @@ -0,0 +1,81 @@ +<template> + <div class="json-editor"> + <textarea ref="textarea" /> + </div> +</template> + +<script> +import CodeMirror from 'codemirror' +import 'codemirror/lib/codemirror.css' +// 替换主题这里需修改名称 +import 'codemirror/theme/idea.css' +import 'codemirror/mode/yaml/yaml' +export default { + props: { + value: { + type: String, + required: true + }, + height: { + type: String, + required: true + } + }, + data() { + return { + editor: false + } + }, + watch: { + value(value) { + const editorValue = this.editor.getValue() + if (value !== editorValue) { + this.editor.setValue(this.value) + } + }, + height(value) { + this.editor.setSize('auto', this.height) + } + }, + mounted() { + this.editor = CodeMirror.fromTextArea(this.$refs.textarea, { + mode: 'text/x-yaml', + lineNumbers: true, + lint: true, + lineWrapping: true, + tabSize: 2, + cursorHeight: 0.9, + // 替换主题这里需修改名称 + theme: 'idea' + }) + this.editor.setSize('auto', this.height) + this.editor.setValue(this.value) + this.editor.on('change', cm => { + this.$emit('changed', cm.getValue()) + this.$emit('input', cm.getValue()) + }) + }, + methods: { + getValue() { + return this.editor.getValue() + } + } +} +</script> + +<style scoped> + .json-editor{ + height: 100%; + margin-bottom: 10px; + } + .json-editor >>> .CodeMirror { + font-size: 13px; + overflow-y:auto; + font-weight:normal + } + .json-editor >>> .CodeMirror-scroll{ + } + .json-editor >>> .cm-s-rubyblue span.cm-string { + color: #F08047; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/directive/clickoutside.js b/UI source code/dns_mapping_ui-master/src/directive/clickoutside.js new file mode 100644 index 0000000..6472bcb --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/directive/clickoutside.js @@ -0,0 +1,50 @@ +export const clickoutside = { + // 初始化指令 + bind(el, binding, vnode) { + function documentHandler(e) { + //这里面执行的是objec ip的代码,需要修改提前说一下 + if (binding.expression == "inputHide") { + if (el.parentNode.parentNode.parentNode.contains(e.target.form)) { + return false; + } + // // 这里判断点击的元素是否是本身,是本身,则返回 + } else if (el.contains(e.target)) { + return false; + } + // // 这里判断点击的元素是否是本身,是本身,则返回 + // console.log(el.parentNode.parentNode.parentNode.contains(e.target.form),'form'); + // // console.log(el.parentNode.parentNode.parentNode,'父亲'); + // console.log(binding,'本身'); + + // if (el.contains(e.target)) { + + // return false; + // } + // 判断指令中是否绑定了函数 + + if (binding.expression) { + // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法 + if (binding.arg) { + if (typeof binding.arg == 'object') { + binding.value(binding.arg); + } else { + binding.value(e, binding.arg); + } + } else { + + binding.value(e); + } + + } + } + // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听 + el.__vueClickOutside__ = documentHandler; + document.addEventListener('click', documentHandler); + }, + unbind(el, binding) { + + // 解除事件监听 + document.removeEventListener('click', el.__vueClickOutside__); + delete el.__vueClickOutside__; + }, +}; diff --git a/UI source code/dns_mapping_ui-master/src/directive/idscope.js b/UI source code/dns_mapping_ui-master/src/directive/idscope.js new file mode 100644 index 0000000..7b7a821 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/directive/idscope.js @@ -0,0 +1,58 @@ +import app from '../main.js' + +//异步写法 暂时不用 +export async function getParentAsync(context, componentPath = '') { + await app.$nextTick(() => { + + }, 10) + return getParent(context, componentPath = '') +} + + +export function getParent(context, componentPath = '') { + var currentIndex = null; + var currentName = null + !context ? context = this : '' + //获取父级节点 + var parent = context && context.$parent || null; + var siblings = (parent && parent.$children) || []; + + currentIndex = siblings.findIndex((item, index) => { + return item._uid === context._uid + }); + currentName = context.$options.name || 'anonymousComponent' + + // var currentPath = currentName + currentIndex //加index,异步组件 会导致索引变化 + var currentPath = currentName + + componentPath = componentPath ? componentPath + '_' + currentPath : currentPath + if (parent) { + return getParent(parent, componentPath) + } + return componentPath +} + +export const idscope = { + bind: function (el, binding, vnode) { + var context = vnode.context; + var id = el.getAttribute('id') || null; + // 同步写法 + var prefix = getParent(context); + if (id) { + var scopedId = id + '-_' + prefix; + el.setAttribute('id', scopedId) + + } + + //异步写法 + // getParentAsync(context).then((prefix) => { + // if (id) { + // var scopedId = id + '-_' + prefix; + // el.setAttribute('id', scopedId) + // } + // }); + } +} + + + diff --git a/UI source code/dns_mapping_ui-master/src/lang/en.js b/UI source code/dns_mapping_ui-master/src/lang/en.js new file mode 100644 index 0000000..faf0d48 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/lang/en.js @@ -0,0 +1,491 @@ +export default { + route: { + dashboard: 'Dashboard', + profile: 'Profile' + }, + navbar: { + setting: 'Settings', + github: 'Repository', + logOut: 'Log Out', + profile: 'Profile', + theme: 'Theme', + docs: 'Document', + size: 'Global Size', + deleteCache: 'DeleteCache' + }, + login: { + title: 'CSE System Login', + logIn: 'Login', + username: 'Username', + password: 'Password', + code: 'Code', + ortherLoginType: 'Orther login type', + chooseToSignIn: 'Sign in with the following account: ', + type: { + up: 'Account Password', + social: 'Third Party Account' + } + }, + documentation: { + documentation: 'Documentation', + github: 'Github Repository' + }, + table: { + region: { + regionName: 'RegionName', + region: 'Region', + node: 'nodeName', + addr: 'Address', + httpsAddr: 'HTTPS', + pulsarAddr: 'Pulsar', + tensorAddr: 'Tensor', + dorisAddr: 'Doris', + redisAddr: 'Redis', + rabbitAddr: 'RabbitMQ', + mariaAddr: 'MariaDB', + minioAddr: 'Minio', + agentAddr: 'Agent', + type: 'Type', + remark: 'Remark', + createTime: 'CreateTime', + id: 'ID', + center: 'Regional Center', + bloc: 'Bloc', + firm: 'Firm', + area: 'Area' + }, + dataConfig: { + configName: 'configName', + actionType: 'actionType', + protocolType: 'protocolType', + dataType: 'dataType', + server: 'server' + }, + system: { + id: 'ID', + host: 'host', + region: 'region', + systemManager: 'systemManager', + managerPhone: 'managerPhone', + managerMail: 'managerMail', + createDate: 'createDate', + systemName: 'systemName', + systemId: 'systemId' + }, + user: { + username: 'UserName', + password: 'Password', + sex: 'Gender', + email: 'Email', + dept: 'Department', + role: 'Role', + mobile: 'Mobile', + status: 'Status', + createTime: 'CreateTime', + modifyTime: 'ModifyTime', + lastLoginTime: 'LastLoginTime', + desc: 'Personal Description', + oldPassword: 'Old Password', + newPassword: 'New Password', + confirmPassword: 'Confirm Again', + social: 'Third Party Account', + dataPermission: 'Data Permission' + }, + role: { + roleName: 'RoleName', + remark: 'Description', + createTime: 'CreateTime', + perms: 'Permissions' + }, + menu: { + parentId: 'Parent', + menuName: 'Name', + type: 'Type', + icon: 'Icon', + component: 'Component', + path: 'URL', + orderNum: 'Order', + perms: 'Permissions' + }, + dept: { + deptName: 'DeptName', + parentId: 'Parent', + orderNum: 'Order' + }, + client: { + clientId: 'clientId', + clientSecret: 'clientSecret', + scope: 'scope', + authorizedGrantTypes: 'authorizedGrantTypes', + accessTokenValidity: 'accessTokenValidity', + refreshTokenValidity: 'refreshTokenValidity', + webServerRedirectUri: 'webServerRedirectUri', + autoapprove: 'autoapprove' + }, + systemLog: { + username: 'UserName', + operation: 'Description', + createTime: 'CreateTime', + time: 'Duration', + method: 'Method', + params: 'parameter', + ip: 'IP', + location: 'Location' + }, + loginLog: { + username: 'UserName', + loginTime: 'LoginTime', + ip: 'IP', + location: 'Location', + system: 'System', + browser: 'Browser', + dataId: 'DataId', + systemId: 'SystemId', + systemName: 'SystemName', + status: 'Status', + targets: 'Targets', + priority: 'Priority', + structure: 'Structure', + dataInfo: 'DataInfo', + files: 'Files', + dataSource: 'DataSource', + timestamp: 'Timestamp', + errorDate: 'ErrorDate' + }, + requestlog: { + requestId: 'RequestId', + systemId: 'SystemId', + createDate: 'CreateDate', + requestMethod: 'RequestMethod', + requestHeader: 'RequestHeader', + requestBody: 'RequestBody', + responseBody: 'ResponseBody', + clientIp: 'ClientIp', + sledIp: 'SledIp', + timestamp: 'Timestamp', + startTime: 'StartTime', + endTime: 'EndTime' + }, + gen: { + config: { + author: 'Author', + basePackage: 'Base Package', + entityPackage: 'Entity Package', + mapperPackage: 'Mapper Package', + mapperXmlPackage: 'Mapper Xml Package', + servicePackage: 'Service Package', + serviceImplPackage: 'ServiceImpl Package', + controllerPackage: 'Controller Package', + isTrim: 'Trim Prefix', + trimValue: 'Trim Value' + }, + generate: { + tableName: 'TableName', + remark: 'Remark', + dataRows: 'DataRows', + createTime: 'CreateTime', + updateTime: 'UpdateTime', + datasource: 'DataSource' + } + }, + job: { + beanName: 'BeanName', + methodName: 'MethodName', + params: 'Params', + cronExpression: 'CronExpression', + status: 'Status', + createTime: 'CreateTime', + executeTime: 'ExecuteTime', + error: 'Error', + time: 'Duration', + remark: 'Remark', + add: 'Create', + delete: 'Delete', + resume: 'Resume', + pause: 'Pause', + run: 'Run once', + fail: 'Fail', + success: 'Success', + normal: 'Normal' + }, + eximport: { + field1: 'Field 1', + field2: 'Field 2', + field3: 'Field 3', + createTime: 'Import Time' + }, + datapermissionTest: { + field1: 'Field 1', + field2: 'Field 2', + field3: 'Field 3', + field4: 'Field 4', + createTime: 'CreateTime', + tips: 'Data permission test, different users see different data' + }, + routeUser: { + tips: 'Gateway management user account list, permissions are divided into ordinary users (user) and administrative users (admin)', + username: 'UserName', + perm: 'Permissions', + createTime: 'CreateTime', + password: 'Password' + }, + routeLog: { + tips: 'Gateway forwards request logs. These are requests that have not been intercepted by traffic limiting or blacklisting rules.', + ip: 'Request IP', + targetServer: 'Target Server', + requestMethod: 'Request Method', + requestTime: 'Request Time', + requestUri: 'Request URI', + targetUri: 'Target URI', + location: 'Location' + }, + rateLimitRule: { + tips: 'Define gateway traffic restriction rules. Requests that do not meet the rules will be intercepted. The interception records can be viewed through the traffic restriction log.', + requestUri: 'Request URI', + requestMethod: 'Request Method', + limitFrom: 'Limit From', + allTheTime: 'all the time', + limitTo: 'Limit To', + count: 'Count', + period: 'Period (Seconds)', + createTime: 'CreateTime', + nst: 'Wildcards are not supported', + status: 'Status', + timeLimit: 'Time Limit', + timeRange: 'Time Range' + }, + rateLimitLog: { + tips: 'Show request logs intercepted by traffic limiting rules', + requestUri: 'Request URI', + requestMethod: 'Request Method', + createTime: 'Request Time', + ip: 'Request IP', + location: 'Location' + }, + blackList: { + tips: 'Define gateway request blacklist', + requestUri: 'Request URI', + requestMethod: 'Request Method', + createTime: 'CreateTime', + ip: 'Request IP', + location: 'Location', + allIp: 'unlimited IP', + limitFrom: 'Limit From', + allTheTime: 'all the time', + limitTo: 'Limit To', + status: 'Status', + st: 'Wildcard support', + timeLimit: 'Time Limit', + timeRange: 'Time Range' + }, + blockLog: { + tips: 'Support wildcards to display request logs intercepted by blacklist rules. Requests that do not meet the rules will be intercepted. The interception records can be viewed through the blacklist logs.', + requestUri: 'Request URI', + requestMethod: 'Request Method', + createTime: 'Request Time', + ip: 'Request IP', + location: 'Location' + }, + routeLogin: { + needLogin: 'The operation of the gateway management module requires authentication, ', + toLogin: ' Click to login', + tips: 'The function of this module needs to be enhanced in advance. For the method of opening, please refer to the document: ', + title: 'CSE Gateway Certification', + login: 'Login' + }, + endpoint: { + serverId: 'Endpoint ID', + serverName: 'Endpoint Name', + serverType: 'Endpoint Type', + bindAddr: 'Binding Address', + serverLocation: 'Endpoint Location', + serverAddr: 'Endpoint Address', + createTime: 'Create Time', + accessKey: 'AccessKey', + accessSecert: 'AccessSecert', + add: 'Add', + delete: 'Delete', + copyAccessKey: 'AccessKey Copied', + copyAccessSecert: 'AccessSecert Copied' + }, + refresh: 'Refresh', + operation: 'Operation', + search: 'Search', + reset: 'Reset', + more: 'More', + add: 'Add', + export: 'Export', + import: 'Import', + templateDownload: 'Template Download', + delete: 'Delete', + resetPassword: 'RestPassword', + openInNewPage: 'New Page' + }, + tagsView: { + refresh: 'Refresh', + close: 'Close', + closeOthers: 'Close Others', + closeAll: 'Close All' + }, + settings: { + title: 'Page style setting', + theme: 'Theme Color', + tagsView: 'Open Tags-View', + fixedHeader: 'Fixed Header', + sidebarLogo: 'Sidebar Logo' + }, + system: { + title: 'CSE System' + }, + tips: { + usernameShouldNotBeEmpty: 'Username can not be empty', + passwordShouldNotBeEmpty: 'Password can not be empty', + switchLanguageSuccess: 'Switch language successfully', + loginSuccess: 'Login successful', + loginFail: 'Login failed', + defaultPassword: 'The user\'s default password is 1234qwer', + getDataFail: 'Failed to get data', + createSuccess: 'Create successfully', + updateSuccess: 'Update successfully', + deleteSuccess: 'Delete successfully', + noDataSelected: 'No data selected yet', + confirmDelete: 'The selected data will be permanently deleted, continue?', + dataUnsaved: 'There are unsaved data', + dataUnfilled: 'There are still unfilled data', + confirmDeleteCache: 'Whether to clear the user permission cache immediately?', + containCurrentUser: 'The operation has been canceled because it contains the currently logged in user', + neverLogin: 'Never logged in to the CSE system', + nothing: 'Nothing', + topId: 'A value of 0 indicates a top-level node', + choose: 'Select: ', + chooseNothing: 'No icons have been selected yet', + onlyChooseOne: 'Only one node can be selected as the parent node', + noNodeSelected: 'Please select a node first', + confirmDeleteNode: 'The selected node and its child nodes will be permanently deleted. Continue?', + iframeGrant: 'Userame: CSE Password: 123456', + notEqual: 'Inconsistent values entered twice', + oldPasswordIncorrect: 'Old password incorrect', + uploadSuccess: 'Upload Successfully', + uploadFailed: 'Upload failed', + onlySupportXlsx: 'Only supports Xlsx type files', + updating: 'Updating', + updateFailed: 'Update failed', + noPermission: 'No permission', + confirmRestPassword: 'Make sure to reset the selected user password?', + resetPasswordSuccess: 'The selected user password reset has been reset to 1234qwer', + getCodeImageFailed: 'Failed to get image verification code', + tooManyRequest: 'Getting the authentication code is too frequent. Please try again later', + clientOriginSecret: 'The original password of the client is: ', + sameRule: 'The same rule already exists', + createTips: 'Please fill in the relevant information in the form', + cronInvalid: 'Cron expression is invalid', + executeSuccess: 'Success', + executeFail: 'Fail' + }, + rules: { + require: 'Can\'t be empty', + range2to10: '2 to 10 characters in length', + range3to10: '3 to 10 characters in length', + range3to20: '3 to 20 characters in length', + range4to10: '4 to 10 characters in length', + range6to20: '6 to 20 characters in length', + email: 'Email is invalid', + mobile: 'Phone number is invalid', + usernameExist: 'The username already exists', + clientIdExist: 'The clientId already exists', + roleNameExist: 'The role name already exists', + noMoreThan10: 'Can\'t exceed 10 characters in length', + noMoreThan11: 'Can\'t exceed 11 characters in length', + noMoreThan20: 'Can\'t exceed 20 characters in length', + noMoreThan50: 'Can\'t exceed 50 characters in length', + noMoreThan100: 'Can\'t exceed 100 characters in length', + invalidInteger: 'Please enter an integer greater than zero', + invalidURL: 'URL is invalid' + }, + common: { + system: 'Microservice Auth System', + desc: { + a: 'Based on Spring Boot 2.2.0 & Spring Cloud Hoxton.RELEASE', + b: 'Use Spring Cloud OAuth2 Unified Authentication', + c: 'Authentication server resource server separation, easy to expand', + d: 'Front-end separation architecture for increased efficiency', + e: 'Integrate multiple monitoring to escort microservices', + f: 'Provide detailed documentation and teach you how to build it', + g: 'Build a highly available microservices cluster by K8S', + h: 'Integrated RocketMQ, TX-LCN, Seata distributed transaction control', + i: 'Data permissions, social login...' + }, + view: 'Detail', + tips: 'Tips', + clear: 'Clear', + confirm: 'Confirm', + cancel: 'Cancel', + add: 'Create', + edit: 'Modify', + username: 'User Name', + dept: 'Department', + createTime: 'Create Time', + yes: 'Yes', + no: 'No', + open: 'Open', + close: 'Close', + sex: { + male: 'Male', + female: 'Female', + secret: 'Secret' + }, + status: { + valid: 'Valid', + invalid: 'Invalid' + }, + menu: { + menu: 'Menu', + button: 'Button' + }, + tab: { + common: 'Common', + directivity: 'Directivity', + solid: 'Solid', + food: 'Food' + }, + aboutMe: 'About Me', + changeAvatar: 'Change', + lastLoginTime: 'Last login time', + goodMorning: 'Good morning', + goodAfternoon: 'Good afternoon', + goodEvening: 'Good evening', + allProject: 'All Projects', + noDept: 'No department', + noRole: 'No role', + firstLogin: 'First login', + you: 'You', + total: 'Total', + visitTitle: 'Nearly ten days of system access records', + timeline: 'Timeline', + account: 'Account', + password: 'Password', + importResult: 'Import Result', + hthz: 'Hou Tian Hanzi', + al: 'Ali Style', + lm: 'Lian Meng', + ctc: 'Click to select', + pleaseInputUrl: 'Please enter a URL', + bind: 'Bind', + unbind: 'Unbind', + confirmUnbind: 'Make sure to unbind the third-party account?', + unbindSuccess: 'Unbind successfully', + bindSuccess: 'Bind successfully', + bindLogin: 'Bind & Login', + signLogin: 'Sign & Login', + current: 'Current ', + socialAccount: ' account ', + socialTips: ' haven\'t bound any system accounts yet, you can bind system accounts or register a new account and bind.', + // 首页统计数 + send: 'Total number of sent data', + receive: 'Total received data', + all: 'Total amount of data transmitted', + systems: 'The total number of business', + indexTimeItem: 'Data transmission situation', + indexTimeCountTitle: 'Data transmission situation' + } +} diff --git a/UI source code/dns_mapping_ui-master/src/lang/index.js b/UI source code/dns_mapping_ui-master/src/lang/index.js new file mode 100644 index 0000000..89a3bd8 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/lang/index.js @@ -0,0 +1,63 @@ +// lang index.js + +import Vue from 'vue' +import VueI18n from 'vue-i18n' +import Cookies from 'js-cookie' +// import { key2Culture } from '@/utils' +import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui lang +import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui lang +import enLocale from './en' +import zhLocale from './zh' + +Vue.use(VueI18n) + +// https://www.cnblogs.com/scode2/p/9098579.html +// https://www.jianshu.com/p/df2550c6f1be +// https://blog.csdn.net/Dream_xun/article/details/82743762 +const messages = { + 'en': { + ...enLocale, + ...elementEnLocale + }, + 'zh': { + ...zhLocale, + ...elementZhLocale + } +} +export function getLanguage() { + const chooseLanguage = Cookies.get('language') + if (chooseLanguage) return chooseLanguage + + // if has not choose language + let localeLang = 'zh' + const language = (navigator.language || navigator.browserLanguage).toLowerCase() + const locales = Object.keys(messages) + for (const locale of locales) { + if (language.indexOf(locale) > -1) { + // return locale + localeLang = locale + break + } + } + + // save to cookie + Cookies.set('language', localeLang) + // const culture = key2Culture(localeLang) + // Cookies.set('.AspNetCore.Culture', `c=${culture}|uic=${culture}`) + Cookies.set('.AspNetCore.Culture', `c=${localeLang}|uic=${localeLang}`) + + return localeLang +} +const i18n = new VueI18n({ + // set locale + // options: en | zh | zh-tw + locale: getLanguage(), + // https://kazupon.github.io/vue-i18n/zh/guide/fallback.html + fallbackLocale: 'en', + silentFallbackWarn: true, + silentTranslationWarn: true, + // set locale messages + messages +}) + +export default i18n diff --git a/UI source code/dns_mapping_ui-master/src/lang/zh.js b/UI source code/dns_mapping_ui-master/src/lang/zh.js new file mode 100644 index 0000000..4136612 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/lang/zh.js @@ -0,0 +1,502 @@ +export default { + route: { + dashboard: '系统主页', + profile: '个人中心' + }, + navbar: { + setting: '系统设置', + github: '项目地址', + logOut: '退出登录', + profile: '个人中心', + docs: '项目文档', + theme: '换肤', + size: '布局大小', + deleteCache: '清除缓存' + }, + login: { + title: 'CSE 系统登录', + logIn: '立即登录', + username: '账号', + password: '密码', + code: '验证码', + ortherLoginType: '其他登录方式', + chooseToSignIn: '选择以下账号登录:', + type: { + up: '账号密码登录', + social: '第三方账号登录' + } + }, + documentation: { + documentation: '项目文档', + github: '项目地址' + }, + table: { + region: { + region: '边云部署节点', + node: '节点名称', + addr: '服务地址', + httpsAddr: 'HTTPS', + pulsarAddr: 'Pulsar', + tensorAddr: 'Tensor', + dorisAddr: 'Doris', + redisAddr: 'Redis', + rabbitAddr: 'RabbitMQ', + mariaAddr: 'MariaDB', + minioAddr: 'Minio', + agentAddr: 'Agent', + type: '节点类型', + remark: '描述信息', + createTime: '创建时间', + id: 'ID', + regionName: '边云节点', + center: '区域中心', + bloc: '集团', + firm: '企业', + area: '区域' + }, + dataConfig: { + configName: '主题', + actionType: '动作', + protocolType: '通信协议', + dataType: '数据类型', + server: '接口地址', + producer: '生产者', + consumer: '消费者' + }, + system: { + id: 'ID', + host: 'host地址', + region: '区域', + systemManager: '负责人', + managerPhone: '负责人电话', + managerMail: '负责人邮箱', + createDate: '创建时间', + systemName: '系统名称', + systemId: '系统ID' + }, + user: { + username: '用户名', + password: '密码', + sex: '性别', + email: '邮箱', + dept: '部门', + role: '角色', + mobile: '电话', + status: '状态', + createTime: '创建时间', + modifyTime: '修改时间', + lastLoginTime: '最后登录时间', + desc: '个人描述', + oldPassword: '旧密码', + newPassword: '新密码', + confirmPassword: '再次确认', + social: '第三方账号', + dataPermission: '数据权限' + }, + role: { + roleName: '角色名称', + remark: '角色描述', + createTime: '创建时间', + perms: '角色权限' + }, + menu: { + parentId: '上级菜单', + menuName: '名称', + type: '类型', + icon: '图标', + component: '组件', + path: 'URL', + orderNum: '排序', + perms: '权限' + }, + dept: { + deptName: '部门名称', + parentId: '上级部门', + orderNum: '排序' + }, + client: { + clientId: '客户端ID', + clientSecret: '客户端秘钥', + scope: '范围', + authorizedGrantTypes: '认证模式', + accessTokenValidity: '访问令牌有效期(秒)', + refreshTokenValidity: '刷新令牌有效期(秒)', + webServerRedirectUri: '重定向地址', + autoapprove: '自动授权' + }, + systemLog: { + username: '操作人', + operation: '操作描述', + createTime: '操作时间', + time: '耗时', + method: '操作方法', + params: '方法参数', + ip: 'IP', + location: '操作地点' + }, + loginLog: { + username: '用户名', + loginTime: '登录时间', + ip: 'IP', + location: '登录地点', + system: '登录系统', + browser: '浏览器', + dataId: '数据ID', + targets: '主题', + status: '数据状态', + dataType: '数据类型', + priority: '优先级', + structure: '数据结构', + dataInfo: '数据体', + files: '数据文件', + dataSource: '数据配置', + systemName: '源业务系统', + systemId: '系统ID', + timestamp: '开始传输时间', + errorDate: '异常时间' + }, + requestlog: { + requestId: '请求ID', + systemId: '业务系统ID', + createDate: '请求时间', + requestMethod: '请求方式', + requestHeader: '请求头', + requestBody: '请求体', + responseBody: '应答体', + clientIp: '客户端IP', + sledIp: '处理机IP', + timestamp: '日志时间', + startTime: '开始时间', + endTime: '结束时间' + }, + gen: { + config: { + author: '作者名称', + basePackage: '基础包名', + entityPackage: 'entity包名', + mapperPackage: 'mapper包名', + mapperXmlPackage: 'mapperXml包名', + servicePackage: 'service包名', + serviceImplPackage: 'serviceImpl包名', + controllerPackage: 'controller包名', + isTrim: '是否去除表前缀', + trimValue: '表前缀' + }, + generate: { + tableName: '表名', + remark: '备注', + dataRows: '数据量(行)', + createTime: '创建时间', + updateTime: '更新时间', + datasource: '数据库' + } + }, + job: { + beanName: 'Bean名称', + methodName: '方法名称', + params: '方法参数', + cronExpression: 'Cron表达式', + status: '状态', + createTime: '创建时间', + executeTime: '执行时间', + error: '错误信息', + time: '耗时', + remark: '备注', + add: '新增', + delete: '删除', + resume: '恢复', + pause: '暂停', + run: '运行一次', + fail: '失败', + success: '成功', + normal: '运行中' + }, + eximport: { + field1: '字段1', + field2: '字段2', + field3: '字段3', + createTime: '导入时间' + }, + datapermissionTest: { + field1: '字段1', + field2: '字段2', + field3: '字段3', + field4: '字段4', + createTime: '创建时间', + tips: '数据权限测试,不同用户看到的数据不一样' + }, + routeUser: { + tips: '网关管理用户账号列表,权限分为普通用户(user)和管理用户(admin)', + username: '用户名', + perm: '权限', + createTime: '创建时间', + password: '密码' + }, + routeLog: { + tips: '网关转发请求日志,这些为未被限流或黑名单规则拦截的请求', + ip: '请求IP', + targetServer: '目标服务', + requestMethod: '请求方法', + requestTime: '请求时间', + requestUri: '请求URI', + targetUri: '目标URI', + location: '请求地址' + }, + rateLimitRule: { + tips: '定义网关限流规则,不符合规则的请求将被拦截,拦截记录可以通过限流日志查看', + requestUri: '请求URI', + requestMethod: '请求方法', + limitFrom: '限制时间起', + allTheTime: '所有时间', + limitTo: '限制时间止', + count: '请求次数', + period: '时间周期(秒)', + createTime: '创建时间', + nst: '不支持通配符', + status: '规则状态', + timeLimit: '时间限制', + timeRange: '时间范围' + }, + rateLimitLog: { + tips: '展示被限流规则拦截的请求日志', + requestUri: '请求URI', + requestMethod: '请求方法', + createTime: '请求时间', + ip: '请求IP', + location: '请求地址' + }, + blackList: { + tips: '定义网关请求黑名单', + requestUri: '请求URI', + requestMethod: '请求方法', + createTime: '创建时间', + ip: '请求IP', + location: '请求地址', + allIp: '所有IP', + limitFrom: '限制时间起', + allTheTime: '所有时间', + limitTo: '限制时间止', + status: '规则状态', + st: '支持通配符', + timeLimit: '时间限制', + timeRange: '时间范围' + }, + blockLog: { + tips: '展示被限流规则拦截的请求日志', + requestUri: '请求URI', + requestMethod: '请求方法', + createTime: '请求时间', + ip: '请求IP', + location: '请求地址' + }, + routeLogin: { + needLogin: '网关管理模块操作需要认证,', + toLogin: '点击认证', + tips: '该模块功能需要预先开启网关增强,开启方法请参考文档:', + title: 'CSE 网关管理认证', + login: '认证' + }, + endpoint: { + serverId: '存储ID', + serverName: '存储名称', + serverType: '存储类别', + bindAddr: '绑定地址', + serverLocation: '存储区域', + serverAddr: '存储地址', + createTime: '创建时间', + accessKey: '接入Key', + accessSecert: '接入秘钥', + add: '新增', + delete: '删除', + copyAccessKey: '接入Key已经复制到剪贴板', + copyAccessSecert: '接入秘钥已经复制到剪贴板' + }, + refresh: '刷新', + operation: '操作', + search: '搜索', + reset: '重置', + more: '更多操作', + add: '添加', + export: '导出', + import: '导入', + templateDownload: '模板下载', + delete: '删除', + resetPassword: '密码重置', + openInNewPage: '新页面打开' + }, + tagsView: { + refresh: '刷新当前', + close: '关闭当前', + closeOthers: '关闭其它', + closeAll: '关闭所有' + }, + settings: { + title: '系统布局配置', + theme: '主题色', + tagsView: '开启 Tags-View', + fixedHeader: '固定 Header', + sidebarLogo: '侧边栏 Logo' + }, + system: { + title: 'CSE 权限系统' + }, + tips: { + usernameShouldNotBeEmpty: '用户名不能为空', + passwordShouldNotBeEmpty: '密码不能为空', + switchLanguageSuccess: '切换语言成功', + loginSuccess: '登录成功', + loginFail: '登录失败', + defaultPassword: '用户的默认密码为1234qwer', + getDataFail: '获取数据失败', + dataUnsaved: '还有未保存的数据', + dataUnfilled: '还有未填选的数据', + createSuccess: '新增成功', + updateSuccess: '修改成功', + deleteSuccess: '删除成功', + noDataSelected: '请先选择需要操作的数据', + confirmDelete: '选中数据将被永久删除, 是否继续?', + confirmDeleteCache: '是否立即清除用户权限缓存?', + containCurrentUser: '包含当前登录用户,操作已取消', + neverLogin: '从未登录过系统', + nothing: '这家伙很懒,什么都没留下', + topId: '值为0时表示顶级节点', + choose: '已选择:', + chooseNothing: '尚未选择任何图标', + onlyChooseOne: '只能选择一个节点作为父节点', + noNodeSelected: '请先选择节点', + confirmDeleteNode: '选中节点及其子结点将被永久删除, 是否继续?', + iframeGrant: '用户名:CSE 密码:123456', + notEqual: '两次输入不一致', + oldPasswordIncorrect: '原密码不正确', + uploadSuccess: '上传成功', + uploadFailed: '上传失败', + onlySupportXlsx: '只支持Xlsx类型文件', + updating: '修改中', + updateFailed: '修改失败', + noPermission: '无权限', + confirmRestPassword: '确定重置所选用户密码?', + resetPasswordSuccess: '所选用户密码重置已被重置为1234qwer', + getCodeImageFailed: '获取图形验证码失败', + tooManyRequest: '获取验证码过于频繁,请稍后再试', + clientOriginSecret: '该客户端秘钥值:', + sameRule: '已存在相同的规则', + createTips: '请在表单中填写相关信息', + cronInvalid: 'Cron表达式不合法', + executeSuccess: '成功', + executeFail: '失败' + }, + rules: { + require: '不能为空', + range2to10: '长度在 2 到 10 个字符', + range3to10: '长度在 3 到 10 个字符', + range3to20: '长度在 3 到 20 个字符', + range4to10: '长度在 4 到 10 个字符', + range6to20: '长度在 6 到 20 个字符', + email: '请输入正确的邮箱地址', + mobile: '请输入合法的手机号', + usernameExist: '该用户名已存在', + systemNameExist: '该系统名称已存在', + systemIdExist: '该系统ID已存在', + clientIdExist: '该Client ID已存在', + roleNameExist: '该角色名称已存在', + noMoreThan10: '长度不能超过10个字符', + noMoreThan11: '长度不能超过11个字符', + noMoreThan20: '长度不能超过20个字符', + noMoreThan50: '长度不能超过50个字符', + noMoreThan100: '长度不能超过100个字符', + invalidInteger: '请输入大于零的整数', + invalidURL: '不是有效的URL' + }, + common: { + system: '分布式微服务权限系统', + desc: { + a: '基于Spring Boot 2.2.0 & Spring Cloud Hoxton.RELEASE', + b: '使用Spring Cloud OAuth2统一认证', + c: '认证服务器资源服务器分离,方便拓展', + d: '前后端分离架构,提高软件开发效率', + e: '集成多种监控,为微服务保驾护航', + f: '提供详细的文档,手把手教你从零搭建到部署', + g: 'Kubernetes搭建高可用微服务集群', + h: '整合RocketMQ、TX-LCN、Seata分布式事务控制', + i: '数据权限,社交登录,开箱即用...' + }, + view: '查看', + tips: '提示', + clear: '清除', + confirm: '确定', + cancel: '取消', + add: '新增', + edit: '修改', + yes: '是', + no: '否', + open: '开启', + close: '关闭', + sex: { + male: '男性', + female: '女性', + secret: '保密' + }, + type: { + center: '区域中心', + bloc: '集团', + firm: '企业' + }, + status: { + valid: '有效', + invalid: '禁用' + }, + menu: { + menu: '菜单', + button: '按钮' + }, + tab: { + common: '通用类', + directivity: '指向性', + solid: '填充类', + food: '食品类' + }, + aboutMe: '关于我', + changeAvatar: '更换头像', + lastLoginTime: '上次登录时间', + goodMorning: '早上好', + goodAfternoon: '下午好', + goodEvening: '晚上好', + allProject: '所有项目', + noDept: '暂无部门', + noRole: '暂无角色', + firstLogin: '第一次登录系统', + you: '您', + total: '总数', + visitTitle: '近十天系统访问记录', + timeline: '登录时间', + account: '账号信息', + password: '个人密码', + importResult: '导入结果', + hthz: '后田花子', + al: '阿里系', + lm: '脸萌', + ctc: '点击选择', + pleaseInputUrl: '请输入URL', + bind: '绑定', + unbind: '解绑', + confirmUnbind: '确定解绑该第三方账号?', + unbindSuccess: '解绑成功', + bindSuccess: '绑定成功', + bindLogin: '绑定并登录', + signLogin: '注册并登录', + current: '当前', + socialAccount: '账号', + socialTips: '尚未绑定任何系统账户,您可以绑定系统账户或者注册一个新的账户并绑定。', + // 首页部分 + send: '发送数据总数', + receive: '接收数据总数', + all: '传输数据总量', + systems: '业务总数', + indexTimeItem: '数据传输态势', + indexTimeCountTitle: '数据传输态势', + transmitAvgRate: '传输平均耗时', + transmitMinRate: '传输最小耗时', + transmitALL: '传输总数', + transmitMaxRate: '传输最大耗时' + } +} diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/AppMain.vue b/UI source code/dns_mapping_ui-master/src/layout/components/AppMain.vue new file mode 100644 index 0000000..1a737b2 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/AppMain.vue @@ -0,0 +1,63 @@ +<template> + <section class="app-main"> + <transition name="fade-transform" mode="out-in"> + <keep-alive :include="cachedViews"> + <router-view :key="key" /> + </keep-alive> + </transition> + <!-- <div v-if="$store.state.settings.showFooter" id="el-main-footer"> + <span v-html="$store.state.settings.footerTxt" /> + <span> ⋅ </span> + <a href="https://beian.miit.gov.cn/#/Integrated/index" target="_blank">{{ $store.state.settings.caseNumber }}</a> + </div> --> + </section> +</template> + +<script> +export default { + name: 'AppMain', + computed: { + cachedViews() { + return this.$store.state.tagsView.cachedViews + }, + key() { + return this.$route.path + } + } +} +</script> + +<style lang="scss" scoped> +.app-main { + /* 50= navbar 50 */ + min-height: calc(100vh - 50px); + width: 100%; + position: relative; + overflow: hidden; + background: #f7f9fc; +} + +.fixed-header+.app-main { + padding-top: 50px; +} + +.hasTagsView { + .app-main { + /* 84 = navbar + tags-view = 50 + 34 */ + min-height: calc(100vh - 84px); + } + + .fixed-header+.app-main { + padding-top: 84px; + } +} +</style> + +<style lang="scss"> +// fix css style bug in open el-dialog +.el-popup-parent--hidden { + .fixed-header { + padding-right: 15px; + } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/FixiOSBug.js b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/FixiOSBug.js new file mode 100644 index 0000000..bc14856 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/FixiOSBug.js @@ -0,0 +1,26 @@ +export default { + computed: { + device() { + return this.$store.state.app.device + } + }, + mounted() { + // In order to fix the click on menu on the ios device will trigger the mouseleave bug + // https://github.com/PanJiaChen/vue-element-admin/issues/1135 + this.fixBugIniOS() + }, + methods: { + fixBugIniOS() { + const $subMenu = this.$refs.subMenu + if ($subMenu) { + const handleMouseleave = $subMenu.handleMouseleave + $subMenu.handleMouseleave = (e) => { + if (this.device === 'mobile') { + return + } + handleMouseleave(e) + } + } + } + } +} diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/Item.vue b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/Item.vue new file mode 100644 index 0000000..b515f61 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/Item.vue @@ -0,0 +1,29 @@ +<script> +export default { + name: 'MenuItem', + functional: true, + props: { + icon: { + type: String, + default: '' + }, + title: { + type: String, + default: '' + } + }, + render(h, context) { + const { icon, title } = context.props + const vnodes = [] + + if (icon) { + vnodes.push(<svg-icon icon-class={icon}/>) + } + + if (title) { + vnodes.push(<span slot='title'>{(title)}</span>) + } + return vnodes + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/Link.vue b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/Link.vue new file mode 100644 index 0000000..eb4dd10 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/Link.vue @@ -0,0 +1,36 @@ + +<template> + <!-- eslint-disable vue/require-component-is --> + <component v-bind="linkProps(to)"> + <slot /> + </component> +</template> + +<script> +import { isExternal } from '@/utils/validate' + +export default { + props: { + to: { + type: String, + required: true + } + }, + methods: { + linkProps(url) { + if (isExternal(url)) { + return { + is: 'a', + href: url, + target: '_blank', + rel: 'noopener' + } + } + return { + is: 'router-link', + to: url + } + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/Logo.vue b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/Logo.vue new file mode 100644 index 0000000..e50a338 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/Logo.vue @@ -0,0 +1,44 @@ +<template> + <div class="log"> + <img :src="logo" alt=""> + <p>DiamondV</p> + </div> +</template> + +<script> +import Logo from '@/assets/images/newlogo.png' +export default { + data() { + return { + logo: Logo + } + } +} +</script> + +<style lang="scss" scoped> + +.log{ + width: 13%; + height: 56px; + background-color: #4608ad; + color: white; + text-align: center; + display: flex; + justify-content:center; + align-items: center; + font-size: 25px; + font-weight: 600; + p{ + font-family:"仿宋"; + font-style:italic; + font-size: 20px; + } + img{ + margin-right: 18px; + width: 50px; + height: 55px; + } +} + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/SidebarItem.vue b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/SidebarItem.vue new file mode 100644 index 0000000..b4d2911 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/SidebarItem.vue @@ -0,0 +1,105 @@ +<template> + <!-- <div v-if="!item.hidden">--> + <!-- todo 增加了style样式 style="display:inline-block;"--> + <div v-if="!item.hidden" style="display:inline-block;"> + <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> + <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> + <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> + <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" /> + </el-menu-item> + </app-link> + </template> + + <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> + <template slot="title"> + <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> + <!--todo 增加div固定宽度,用于菜单上的小箭头显示--> + <div style="display: inline-block; width:20px;" /> + </template> + <sidebar-item + v-for="child in item.children" + :key="child.path" + :is-nest="true" + :item="child" + :base-path="resolvePath(child.path)" + class="nest-menu" + /> + </el-submenu> + </div> +</template> + +<script> +import path from 'path' +import { isExternal } from '@/utils/validate' +import Item from './Item' +import AppLink from './Link' +import FixiOSBug from './FixiOSBug' + +export default { + name: 'SidebarItem', + components: { Item, AppLink }, + mixins: [FixiOSBug], + props: { + // route object + item: { + type: Object, + required: true + }, + isNest: { + type: Boolean, + default: false + }, + basePath: { + type: String, + default: '' + } + }, + data() { + // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237 + // TODO: refactor with render function + this.onlyOneChild = null + return {} + }, + methods: { + hasOneShowingChild(children = [], parent) { + const showingChildren = children.filter(item => { + if (item.hidden) { + return false + } else { + // Temp set(will be used if only has one showing child) + this.onlyOneChild = item + return true + } + }) + + // When there is only one child router, the child router is displayed by default + if (showingChildren.length === 1) { + return true + } + + // Show parent if there are no child router to display + if (showingChildren.length === 0) { + this.onlyOneChild = { ... parent, path: '', noShowingChildren: true } + return true + } + + return false + }, + resolvePath(routePath) { + if (isExternal(routePath)) { + return routePath + } + if (isExternal(this.basePath)) { + return this.basePath + } + return path.resolve(this.basePath, routePath) + } + } +} +</script> +<style scoped> +.el-menu-item { + font-size: 17px; + color: white !important; +} +</style>
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/index.vue b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/index.vue new file mode 100644 index 0000000..1076b36 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/HeadNavbar/index.vue @@ -0,0 +1,90 @@ +<template> + <!-- <div :class="{'has-logo':showLogo}" > --> + <div class="menu"> + <!--TODO 文章中删除了logo,有验证了一次,可以不删除--> + <!-- <logo v-if="showLogo" :collapse="isCollapse"/> --> + <Logo /> + <el-scrollbar id="navlist" wrap-class="scrollbar-wrapper"> + <!--TODO 将el-menu标签下的mode属性更改为horizontal--> + <!-- <span>1111</span> --> + <el-menu + :default-active="activeMenu" + :collapse="isCollapse" + :background-color="variables.menuBg" + :text-color="variables.menuText" + :unique-opened="false" + :active-text-color="variables.menuActiveText" + :collapse-transition="false" + mode="horizontal" + > + <sidebar-item v-for="route in sidebarRouters" :key="route.path" :item="route" :base-path="route.path" /> + </el-menu> + </el-scrollbar> + <navbar /> + </div> +</template> + +<script> +import { mapGetters } from 'vuex' +import SidebarItem from './SidebarItem' +import variables from '@/assets/styles/variables.scss' +import Navbar from '../Navbar.vue' +import Logo from './Logo.vue' + +export default { + // components: {Logo }, + components: { SidebarItem, Navbar, Logo }, + computed: { + ...mapGetters([ + 'sidebarRouters', + 'sidebar' + ]), + activeMenu() { + const route = this.$route + const { meta, path } = route + // if set path, the sidebar will highlight the path you set + if (meta.activeMenu) { + return meta.activeMenu + } + return path + }, + showLogo() { + return this.$store.state.settings.sidebarLogo + }, + variables() { + return variables + }, + isCollapse() { + return !this.sidebar.opened + } + } +} +</script> +<style lang="scss" scoped> +.menu{ + display: flex; +} +#navlist { +width: 80% !important; +float: left; +} + + #navlist >>> .el-submenu__title { + font-weight: 100; + font-size:18px !important; + color: white !important; + } + #navlist >>> .is-active{ + font-size: 18px !important; + font-weight: 600 !important; + background-color: rgb(50, 4, 122) !important; + } + #navlist >>> .el-scrollbar__wrap{ + margin-bottom: 0px; + overflow: hidden; + } +/* .el-scrollbar__view{ + display: flex; +} */ + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/Navbar.vue b/UI source code/dns_mapping_ui-master/src/layout/components/Navbar.vue new file mode 100644 index 0000000..e763c91 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/Navbar.vue @@ -0,0 +1,210 @@ +<template> + <div class="navbar"> + <!-- <hamburger + v-if="menuInLeft" + id="hamburger-container" + :is-active="sidebar.opened" + class="hamburger-container" + @toggleClick="toggleSideBar" + /> --> + + <!-- <breadcrumb id="breadcrumb-container" class="breadcrumb-container" /> --> + + <div class="right-menu"> + <!-- <template v-if="device !== 'mobile'"> + <search id="header-search" class="right-menu-item" /> + + <el-tooltip content="项目文档" effect="dark" placement="bottom"> + <Doc class="right-menu-item hover-effect" /> + </el-tooltip> + + <el-tooltip content="全屏缩放" effect="dark" placement="bottom"> + <screenfull id="screenfull" class="right-menu-item hover-effect" /> + </el-tooltip> + + <el-tooltip content="布局设置" effect="dark" placement="bottom"> + <size-select id="size-select" class="right-menu-item hover-effect" /> + </el-tooltip> + </template> --> + + <el-dropdown + class="avatar-container right-menu-item hover-effect" + trigger="click" + > + <div class="avatar-wrapper"> + <!-- <img + :src=" + user.avatarName ? baseApi + '/avatar/' + user.avatarName : Avatar + " + class="user-avatar" + /> --> + <i class="el-icon-user" /> + <!-- <span>{{user.content.createBy}}</span> --> + <span>{{ user.username }}</span> + <i class="el-icon-caret-bottom" /> + </div> + <el-dropdown-menu slot="dropdown"> + <!-- <span style="display: block" @click="show = true"> + <el-dropdown-item> 布局设置 </el-dropdown-item> + </span> + <router-link to="/user/center"> + <el-dropdown-item> 个人中心 </el-dropdown-item> + </router-link> --> + <span style="display: block" @click="open"> + <el-dropdown-item divided> 退出登录 </el-dropdown-item> + </span> + </el-dropdown-menu> + </el-dropdown> + </div> + </div> +</template> + +<script> +import { mapGetters, mapState } from 'vuex' +// import Breadcrumb from "@/components/Breadcrumb"; +// import Hamburger from "@/components/Hamburger"; +// import Doc from "@/components/Doc"; +// import Screenfull from "@/components/Screenfull"; +// import SizeSelect from "@/components/SizeSelect"; +// import Search from "@/components/HeaderSearch"; +// import Avatar from "@/assets/images/avatar.png"; + +export default { + components: { + // Breadcrumb, + // Hamburger, + // Screenfull, + // SizeSelect, + // Search, + // Doc, + }, + data() { + return { + // Avatar: Avatar, + dialogVisible: false + } + }, + computed: { + ...mapGetters(['sidebar', 'device', 'user', 'baseApi']), + ...mapState({ + menuInLeft: state => state.settings.menuInLeft + }), + show: { + get() { + return this.$store.state.settings.showSettings + }, + set(val) { + this.$store.dispatch('settings/changeSetting', { + key: 'showSettings', + value: val + }) + } + } + }, + methods: { + toggleSideBar() { + this.$store.dispatch('app/toggleSideBar') + }, + open() { + this.$confirm('确定注销并退出系统吗?', '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + this.logout() + }) + }, + logout() { + this.$store.dispatch('LogOut').then(() => { + location.reload() + }) + } + } +} +</script> + +<style lang="scss" scoped> +.navbar { + width: 10%; + height: 56px; + overflow: hidden; + position: relative; + background: #4608ad; + // box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); + + // .hamburger-container { + // line-height: 46px; + // height: 100%; + // float: left; + // cursor: pointer; + // transition: background 0.3s; + // -webkit-tap-highlight-color: transparent; + + // &:hover { + // background: rgba(0, 0, 0, 0.025); + // } + // } + + // .breadcrumb-container { + // float: left; + // } + + // .errLog-container { + // display: inline-block; + // vertical-align: top; + // } + + .right-menu { + // float: right; + height: 100%; + line-height: 50px; + + &:focus { + outline: none; + } + + .right-menu-item { + display: inline-block; + padding: 0 8px; + height: 100%; + font-size: 18px; + color: #5a5e66; + vertical-align: text-bottom; + + &.hover-effect { + cursor: pointer; + transition: background 0.3s; + + &:hover { + background: rgba(0, 0, 0, 0.025); + } + } + } + + .avatar-container { + margin-right: 30px; + + .avatar-wrapper { + margin-top: 5px; + position: relative; + color: white; + + // .user-avatar { + // cursor: pointer; + // width: 40px; + // height: 40px; + // border-radius: 10px; + // } + + .el-icon-caret-bottom { + cursor: pointer; + position: absolute; + right: -20px; + top: 25px; + font-size: 12px; + } + } + } + } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/Settings/index.vue b/UI source code/dns_mapping_ui-master/src/layout/components/Settings/index.vue new file mode 100644 index 0000000..3ed8092 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/Settings/index.vue @@ -0,0 +1,141 @@ +<template> + <div class="drawer-container"> + <div> + <h3 class="drawer-title">系统布局设置</h3> + + <div class="drawer-item"> + <span>主题颜色</span> + <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" /> + </div> + + <div class="drawer-item"> + <span>显示标签</span> + <el-switch v-model="tagsView" class="drawer-switch" /> + </div> + + <div class="drawer-item"> + <span>固定头部</span> + <el-switch v-model="fixedHeader" class="drawer-switch" /> + </div> + + <div class="drawer-item"> + <span>显示LOGO</span> + <el-switch v-model="sidebarLogo" class="drawer-switch" /> + </div> + + <div class="drawer-item"> + <span>菜单UniqueOpened</span> + <el-switch v-model="uniqueOpened" class="drawer-switch" /> + </div> + + <div class="drawer-item"> + <span>切换菜单位置</span> + <el-switch v-model="menuInLeft" class="drawer-switch" /> + </div> + + </div> + </div> +</template> + +<script> +import ThemePicker from '@/components/ThemePicker' + +export default { + components: { ThemePicker }, + data() { + return {} + }, + computed: { + fixedHeader: { + get() { + return this.$store.state.settings.fixedHeader + }, + set(val) { + this.$store.dispatch('settings/changeSetting', { + key: 'fixedHeader', + value: val + }) + } + }, + tagsView: { + get() { + return this.$store.state.settings.tagsView + }, + set(val) { + this.$store.dispatch('settings/changeSetting', { + key: 'tagsView', + value: val + }) + } + }, + sidebarLogo: { + get() { + return this.$store.state.settings.sidebarLogo + }, + set(val) { + this.$store.dispatch('settings/changeSetting', { + key: 'sidebarLogo', + value: val + }) + } + }, + uniqueOpened: { + get() { + return this.$store.state.settings.uniqueOpened + }, + set(val) { + this.$store.dispatch('settings/changeSetting', { + key: 'uniqueOpened', + value: val + }) + } + }, + // 增加绑定的menuInLeft值 + menuInLeft: { + get() { + return this.$store.state.settings.menuInLeft + }, + set(val) { + this.$store.dispatch('settings/changeSetting', { + key: 'menuInLeft', + value: val + }) + } + } + }, + methods: { + themeChange(val) { + this.$store.dispatch('settings/changeSetting', { + key: 'theme', + value: val + }) + } + } +} +</script> + +<style lang="scss" scoped> +.drawer-container { + padding: 24px; + font-size: 14px; + line-height: 1.5; + word-wrap: break-word; + + .drawer-title { + margin-bottom: 12px; + color: rgba(0, 0, 0, .85); + font-size: 14px; + line-height: 22px; + } + + .drawer-item { + color: rgba(0, 0, 0, .65); + font-size: 14px; + padding: 12px 0; + } + + .drawer-switch { + float: right + } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/FixiOSBug.js b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/FixiOSBug.js new file mode 100644 index 0000000..bc14856 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/FixiOSBug.js @@ -0,0 +1,26 @@ +export default { + computed: { + device() { + return this.$store.state.app.device + } + }, + mounted() { + // In order to fix the click on menu on the ios device will trigger the mouseleave bug + // https://github.com/PanJiaChen/vue-element-admin/issues/1135 + this.fixBugIniOS() + }, + methods: { + fixBugIniOS() { + const $subMenu = this.$refs.subMenu + if ($subMenu) { + const handleMouseleave = $subMenu.handleMouseleave + $subMenu.handleMouseleave = (e) => { + if (this.device === 'mobile') { + return + } + handleMouseleave(e) + } + } + } + } +} diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/Item.vue b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/Item.vue new file mode 100644 index 0000000..b515f61 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/Item.vue @@ -0,0 +1,29 @@ +<script> +export default { + name: 'MenuItem', + functional: true, + props: { + icon: { + type: String, + default: '' + }, + title: { + type: String, + default: '' + } + }, + render(h, context) { + const { icon, title } = context.props + const vnodes = [] + + if (icon) { + vnodes.push(<svg-icon icon-class={icon}/>) + } + + if (title) { + vnodes.push(<span slot='title'>{(title)}</span>) + } + return vnodes + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/Link.vue b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/Link.vue new file mode 100644 index 0000000..eb4dd10 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/Link.vue @@ -0,0 +1,36 @@ + +<template> + <!-- eslint-disable vue/require-component-is --> + <component v-bind="linkProps(to)"> + <slot /> + </component> +</template> + +<script> +import { isExternal } from '@/utils/validate' + +export default { + props: { + to: { + type: String, + required: true + } + }, + methods: { + linkProps(url) { + if (isExternal(url)) { + return { + is: 'a', + href: url, + target: '_blank', + rel: 'noopener' + } + } + return { + is: 'router-link', + to: url + } + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/Logo.vue b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/Logo.vue new file mode 100644 index 0000000..1233dcd --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/Logo.vue @@ -0,0 +1,82 @@ +<template> + <div class="sidebar-logo-container" :class="{'collapse':collapse}"> + <transition name="sidebarLogoFade"> + <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> + <img v-if="logo" :src="logo" class="sidebar-logo"> + <h1 v-else class="sidebar-title">{{ title }} </h1> + </router-link> + <router-link v-else key="expand" class="sidebar-logo-link" to="/"> + <img v-if="logo" :src="logo" class="sidebar-logo"> + <h1 class="sidebar-title">{{ title }} </h1> + </router-link> + </transition> + </div> +</template> + +<script> +import Logo from '@/assets/images/logo.png' +export default { + name: 'SidebarLogo', + props: { + collapse: { + type: Boolean, + required: true + } + }, + data() { + return { + title: 'DiamondV后台管理', + logo: Logo + } + } +} +</script> + +<style lang="scss" scoped> +.sidebarLogoFade-enter-active { + transition: opacity 1.5s; +} + +.sidebarLogoFade-enter, +.sidebarLogoFade-leave-to { + opacity: 0; +} + +.sidebar-logo-container { + position: relative; + width: 100%; + height: 50px; + line-height: 50px; + text-align: center; + overflow: hidden; + + & .sidebar-logo-link { + height: 100%; + width: 100%; + + & .sidebar-logo { + width: 32px; + height: 32px; + vertical-align: middle; + margin-right: 6px; + } + + & .sidebar-title { + display: inline-block; + margin: 0; + color: #fff; + font-weight: 600; + line-height: 50px; + font-size: 14px; + font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; + vertical-align: middle; + } + } + + &.collapse { + .sidebar-logo { + margin-right: 0px; + } + } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/SidebarItem.vue b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/SidebarItem.vue new file mode 100644 index 0000000..2d49dd8 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/SidebarItem.vue @@ -0,0 +1,95 @@ +<template> + <div v-if="!item.hidden" class="menu-wrapper"> + <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> + <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> + <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> + <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" /> + </el-menu-item> + </app-link> + </template> + + <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> + <template slot="title"> + <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> + </template> + <sidebar-item + v-for="child in item.children" + :key="child.path" + :is-nest="true" + :item="child" + :base-path="resolvePath(child.path)" + class="nest-menu" + /> + </el-submenu> + </div> +</template> + +<script> +import path from 'path' +import { isExternal } from '@/utils/validate' +import Item from './Item' +import AppLink from './Link' +import FixiOSBug from './FixiOSBug' + +export default { + name: 'SidebarItem', + components: { Item, AppLink }, + mixins: [FixiOSBug], + props: { + // route object + item: { + type: Object, + required: true + }, + isNest: { + type: Boolean, + default: false + }, + basePath: { + type: String, + default: '' + } + }, + data() { + // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237 + // TODO: refactor with render function + this.onlyOneChild = null + return {} + }, + methods: { + hasOneShowingChild(children = [], parent) { + const showingChildren = children.filter(item => { + if (item.hidden) { + return false + } else { + // Temp set(will be used if only has one showing child) + this.onlyOneChild = item + return true + } + }) + + // When there is only one child router, the child router is displayed by default + if (showingChildren.length === 1) { + return true + } + + // Show parent if there are no child router to display + if (showingChildren.length === 0) { + this.onlyOneChild = { ... parent, path: '', noShowingChildren: true } + return true + } + + return false + }, + resolvePath(routePath) { + if (isExternal(routePath)) { + return routePath + } + if (isExternal(this.basePath)) { + return this.basePath + } + return path.resolve(this.basePath, routePath) + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/index.vue b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/index.vue new file mode 100644 index 0000000..b192bd2 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/Sidebar/index.vue @@ -0,0 +1,56 @@ +<template> + <div :class="{ 'has-logo': showLogo }"> + <logo v-if="showLogo" :collapse="isCollapse" /> + <el-scrollbar wrap-class="scrollbar-wrapper"> + <el-menu + :default-active="activeMenu" + :collapse="isCollapse" + :background-color="variables.menuBg" + :text-color="variables.menuText" + :unique-opened="$store.state.settings.uniqueOpened" + :active-text-color="variables.menuActiveText" + :collapse-transition="false" + mode="vertical" + > + <sidebar-item + v-for="route in sidebarRouters" + :key="route.path" + :item="route" + :base-path="route.path" + /> + </el-menu> + </el-scrollbar> + </div> +</template> + +<script> +import { mapGetters } from 'vuex' +import Logo from './Logo' +import SidebarItem from './SidebarItem' +import variables from '@/assets/styles/variables.scss' + +export default { + components: { SidebarItem, Logo }, + computed: { + ...mapGetters(['sidebarRouters', 'sidebar']), + activeMenu() { + const route = this.$route + const { meta, path } = route + // if set path, the sidebar will highlight the path you set + if (meta.activeMenu) { + return meta.activeMenu + } + return path + }, + showLogo() { + return this.$store.state.settings.sidebarLogo + }, + variables() { + return variables + }, + isCollapse() { + return !this.sidebar.opened + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/TagsView/ScrollPane.vue b/UI source code/dns_mapping_ui-master/src/layout/components/TagsView/ScrollPane.vue new file mode 100644 index 0000000..018f1aa --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/TagsView/ScrollPane.vue @@ -0,0 +1,86 @@ +<template> + <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll"> + <slot /> + </el-scrollbar> +</template> + +<script> +const tagAndTagSpacing = 4 // tagAndTagSpacing + +export default { + name: 'ScrollPane', + data() { + return { + left: 0 + } + }, + computed: { + scrollWrapper() { + return this.$refs.scrollContainer.$refs.wrap + } + }, + methods: { + handleScroll(e) { + const eventDelta = e.wheelDelta || -e.deltaY * 40 + const $scrollWrapper = this.scrollWrapper + $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4 + }, + moveToTarget(currentTag) { + const $container = this.$refs.scrollContainer.$el + const $containerWidth = $container.offsetWidth + const $scrollWrapper = this.scrollWrapper + const tagList = this.$parent.$refs.tag + + let firstTag = null + let lastTag = null + + // find first tag and last tag + if (tagList.length > 0) { + firstTag = tagList[0] + lastTag = tagList[tagList.length - 1] + } + + if (firstTag === currentTag) { + $scrollWrapper.scrollLeft = 0 + } else if (lastTag === currentTag) { + $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth + } else { + // find preTag and nextTag + const currentIndex = tagList.findIndex(item => item === currentTag) + const prevTag = tagList[currentIndex - 1] + const nextTag = tagList[currentIndex + 1] + + // the tag's offsetLeft after of nextTag + const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing + + // the tag's offsetLeft before of prevTag + const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing + + if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) { + $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth + } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) { + $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft + } + } + } + } +} +</script> + +<style lang="scss" scoped> +.scroll-container { + white-space: nowrap; + position: relative; + overflow: hidden; + width: 100%; + ::v-deep { + .el-scrollbar__bar { + bottom: 0px; + } + .el-scrollbar__wrap { + height: 49px; + // width: 80% !important; + } + } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/TagsView/index.vue b/UI source code/dns_mapping_ui-master/src/layout/components/TagsView/index.vue new file mode 100644 index 0000000..9dd84f9 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/TagsView/index.vue @@ -0,0 +1,286 @@ +<template> + <div id="tags-view-container" class="tags-view-container"> + <scroll-pane ref="scrollPane" class="tags-view-wrapper"> + <router-link + v-for="tag in visitedViews" + ref="tag" + :key="tag.path" + :class="isActive(tag)?'active':''" + :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" + tag="span" + class="tags-view-item" + @click.middle.native="closeSelectedTag(tag)" + @contextmenu.prevent.native="openMenu(tag,$event)" + > + {{ tag.title }} + <span v-if="!tag.meta.affix" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /> + </router-link> + </scroll-pane> + <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu"> + <li @click="refreshSelectedTag(selectedTag)">刷新</li> + <li v-if="!(selectedTag.meta&&selectedTag.meta.affix)" @click="closeSelectedTag(selectedTag)">关闭</li> + <li @click="closeOthersTags">关闭其他</li> + <li @click="closeAllTags(selectedTag)">关闭全部</li> + </ul> + </div> +</template> + +<script> +import ScrollPane from './ScrollPane' +import path from 'path' + +export default { + components: { ScrollPane }, + data() { + return { + visible: false, + top: 0, + left: 0, + selectedTag: {}, + affixTags: [] + } + }, + computed: { + visitedViews() { + return this.$store.state.tagsView.visitedViews + }, + routes() { + return this.$store.state.permission.routers + } + }, + watch: { + $route() { + this.addTags() + this.moveToCurrentTag() + }, + visible(value) { + if (value) { + document.body.addEventListener('click', this.closeMenu) + } else { + document.body.removeEventListener('click', this.closeMenu) + } + } + }, + mounted() { + this.initTags() + this.addTags() + }, + methods: { + isActive(route) { + return route.path === this.$route.path + }, + filterAffixTags(routes, basePath = '/') { + let tags = [] + routes.forEach(route => { + if (route.meta && route.meta.affix) { + const tagPath = path.resolve(basePath, route.path) + tags.push({ + fullPath: tagPath, + path: tagPath, + name: route.name, + meta: { ...route.meta } + }) + } + if (route.children) { + const tempTags = this.filterAffixTags(route.children, route.path) + if (tempTags.length >= 1) { + tags = [...tags, ...tempTags] + } + } + }) + return tags + }, + initTags() { + const affixTags = this.affixTags = this.filterAffixTags(this.routes) + for (const tag of affixTags) { + // Must have tag name + if (tag.name) { + this.$store.dispatch('tagsView/addVisitedView', tag) + } + } + }, + addTags() { + const { name } = this.$route + if (name) { + this.$store.dispatch('tagsView/addView', this.$route) + } + return false + }, + moveToCurrentTag() { + const tags = this.$refs.tag + this.$nextTick(() => { + for (const tag of tags) { + if (tag.to.path === this.$route.path) { + this.$refs.scrollPane.moveToTarget(tag) + // when query is different then update + if (tag.to.fullPath !== this.$route.fullPath) { + this.$store.dispatch('tagsView/updateVisitedView', this.$route) + } + break + } + } + }) + }, + refreshSelectedTag(view) { + this.$store.dispatch('tagsView/delCachedView', view).then(() => { + const { fullPath } = view + this.$nextTick(() => { + this.$router.replace({ + path: '/redirect' + fullPath + }) + }) + }) + }, + closeSelectedTag(view) { + this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => { + if (this.isActive(view)) { + this.toLastView(visitedViews, view) + } + }) + }, + closeOthersTags() { + this.$router.push(this.selectedTag) + this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => { + this.moveToCurrentTag() + }) + }, + closeAllTags(view) { + this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => { + if (this.affixTags.some(tag => tag.path === view.path)) { + return + } + this.toLastView(visitedViews, view) + }) + }, + toLastView(visitedViews, view) { + const latestView = visitedViews.slice(-1)[0] + if (latestView) { + this.$router.push(latestView) + } else { + // now the default is to redirect to the home page if there is no tags-view, + // you can adjust it according to your needs. + if (view.name === 'Dashboard') { + // to reload home page + this.$router.replace({ path: '/redirect' + view.fullPath }) + } else { + this.$router.push('/') + } + } + }, + openMenu(tag, e) { + const menuMinWidth = 105 + const offsetLeft = this.$el.getBoundingClientRect().left // container margin left + const offsetWidth = this.$el.offsetWidth // container width + const maxLeft = offsetWidth - menuMinWidth // left boundary + const left = e.clientX - offsetLeft + 15 // 15: margin right + + if (left > maxLeft) { + this.left = maxLeft + } else { + this.left = left + } + + this.top = e.clientY + this.visible = true + this.selectedTag = tag + }, + closeMenu() { + this.visible = false + } + } +} +</script> + +<style lang="scss" scoped> +.tags-view-container { + height: 34px; + width: 100%; + background: #fff; + border-bottom: 1px solid #d8dce5; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04); + .tags-view-wrapper { + .tags-view-item { + display: inline-block; + position: relative; + cursor: pointer; + height: 26px; + line-height: 26px; + border: 1px solid #d8dce5; + color: #495060; + background: #fff; + padding: 0 8px; + font-size: 12px; + margin-left: 5px; + margin-top: 4px; + &:first-of-type { + margin-left: 15px; + } + &:last-of-type { + margin-right: 15px; + } + &.active { + background-color: #42b983; + color: #fff; + border-color: #42b983; + &::before { + content: ''; + background: #fff; + display: inline-block; + width: 8px; + height: 8px; + border-radius: 50%; + position: relative; + margin-right: 2px; + } + } + } + } + .contextmenu { + margin: 0; + background: #fff; + z-index: 3000; + position: absolute; + list-style-type: none; + padding: 5px 0; + border-radius: 4px; + font-size: 12px; + font-weight: 400; + color: #333; + box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3); + li { + margin: 0; + padding: 7px 16px; + cursor: pointer; + &:hover { + background: #eee; + } + } + } +} +</style> + +<style lang="scss"> +//reset element css of el-icon-close +.tags-view-wrapper { + .tags-view-item { + .el-icon-close { + width: 16px; + height: 16px; + vertical-align: 2px; + border-radius: 50%; + text-align: center; + transition: all .3s cubic-bezier(.645, .045, .355, 1); + transform-origin: 100% 50%; + &:before { + transform: scale(.6); + display: inline-block; + vertical-align: -3px; + } + &:hover { + background-color: #b4bccc; + color: #fff; + } + } + } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/layout/components/index.js b/UI source code/dns_mapping_ui-master/src/layout/components/index.js new file mode 100644 index 0000000..61ef939 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/components/index.js @@ -0,0 +1,6 @@ +export { default as AppMain } from './AppMain' +export { default as Navbar } from './Navbar' +export { default as HeadNavbar } from './HeadNavbar/index.vue' +export { default as Settings } from './Settings' +export { default as Sidebar } from './Sidebar/index.vue' +export { default as TagsView } from './TagsView/index.vue' diff --git a/UI source code/dns_mapping_ui-master/src/layout/index.vue b/UI source code/dns_mapping_ui-master/src/layout/index.vue new file mode 100644 index 0000000..6e83e5c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/index.vue @@ -0,0 +1,118 @@ +<template> + <div :class="classObj" class="app-wrapper"> + <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> + <sidebar v-if="menuInLeft" class="sidebar-container" /> + <div :class="{hasTagsView:needTagsView,'main-container':menuInLeft}" class="main-container"> + <div :class="{'fixed-header':fixedHeader}"> + <!-- <navbar /> --> + <HeadNavbar v-if="!menuInLeft" /> + <!-- <tags-view v-if="needTagsView" /> --> + </div> + <app-main /> + <right-panel v-if="showSettings"> + <settings /> + </right-panel> + </div> + <!-- 防止刷新后主题丢失 --> + <Theme v-show="false" ref="theme" /> + </div> +</template> + +<script> +import RightPanel from '@/components/RightPanel' +import { AppMain, Navbar, Settings, Sidebar, TagsView, HeadNavbar } from './components' +import ResizeMixin from './mixin/ResizeHandler' +import { mapState } from 'vuex' +import Theme from '@/components/ThemePicker' +import Cookies from 'js-cookie' +export default { + name: 'Layout', + components: { + AppMain, + RightPanel, + HeadNavbar, + Settings, + Sidebar, + TagsView, + Theme + }, + mixins: [ResizeMixin], + computed: { + ...mapState({ + sidebar: state => state.app.sidebar, + device: state => state.app.device, + showSettings: state => state.settings.showSettings, + needTagsView: state => state.settings.tagsView, + fixedHeader: state => state.settings.fixedHeader, + menuInLeft: state => state.settings.menuInLeft + }), + classObj() { + return { + hideSidebar: !this.sidebar.opened, + openSidebar: this.sidebar.opened, + withoutAnimation: this.sidebar.withoutAnimation, + mobile: this.device === 'mobile' + } + } + }, + mounted() { + if (Cookies.get('theme')) { + this.$refs.theme.theme = Cookies.get('theme') + this.$store.dispatch('settings/changeSetting', { + key: 'theme', + value: Cookies.get('theme') + }) + } + }, + methods: { + handleClickOutside() { + this.$store.dispatch('app/closeSideBar', { withoutAnimation: false }) + } + } +} +</script> + +<style lang="scss" scoped> + @import "~@/assets/styles/mixin.scss"; + @import "~@/assets/styles/variables.scss"; + + .rapper { + @include clearfix; + position: relative; + height: 100%; + // width: 100%; + + &.mobile.openSidebar { + position: fixed; + top: 0; + } + } + + .drawer-bg { + background: #000; + opacity: 0.3; + width: 100%; + top: 0; + height: 100%; + position: absolute; + z-index: 999; + } + + .fixed-header { + position: fixed; + top: 0; + right: 0; + z-index: 9; + width: calc(100% - #{$sideBarWidth}); + transition: width 0.28s; + padding: 0; + } + + .hideSidebar .fixed-header { + width: calc(100% - 54px) + } + + .mobile .fixed-header { + width: 100%; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/layout/mixin/ResizeHandler.js b/UI source code/dns_mapping_ui-master/src/layout/mixin/ResizeHandler.js new file mode 100644 index 0000000..e8d0df8 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/layout/mixin/ResizeHandler.js @@ -0,0 +1,45 @@ +import store from '@/store' + +const { body } = document +const WIDTH = 992 // refer to Bootstrap's responsive design + +export default { + watch: { + $route(route) { + if (this.device === 'mobile' && this.sidebar.opened) { + store.dispatch('app/closeSideBar', { withoutAnimation: false }) + } + } + }, + beforeMount() { + window.addEventListener('resize', this.$_resizeHandler) + }, + beforeDestroy() { + window.removeEventListener('resize', this.$_resizeHandler) + }, + mounted() { + const isMobile = this.$_isMobile() + if (isMobile) { + store.dispatch('app/toggleDevice', 'mobile') + store.dispatch('app/closeSideBar', { withoutAnimation: true }) + } + }, + methods: { + // use $_ for mixins properties + // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential + $_isMobile() { + const rect = body.getBoundingClientRect() + return rect.width - 1 < WIDTH + }, + $_resizeHandler() { + if (!document.hidden) { + const isMobile = this.$_isMobile() + store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop') + + if (isMobile) { + store.dispatch('app/closeSideBar', { withoutAnimation: true }) + } + } + } + } +} diff --git a/UI source code/dns_mapping_ui-master/src/main.js b/UI source code/dns_mapping_ui-master/src/main.js new file mode 100644 index 0000000..c66014f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/main.js @@ -0,0 +1,74 @@ +import Vue from 'vue' + +import Cookies from 'js-cookie' + +import 'normalize.css/normalize.css' + +import Element from 'element-ui' +// +import mavonEditor from 'mavon-editor' +import 'mavon-editor/dist/css/index.css' + +import i18n from './lang' + +// 数据字典 +import dict from './components/Dict' + +// 权限指令 +import checkPer from '@/utils/permission' +import permission from './components/Permission' +import './assets/styles/element-variables.scss' +// global css +import './assets/styles/index.scss' + +// 代码高亮 +import VueHighlightJS from 'vue-highlightjs' +import 'highlight.js/styles/atom-one-dark.css' +// 引入echarts +import echarts from 'echarts' +Vue.prototype.$echarts = echarts +// 引入中国地图 +import china from 'echarts/map/json/china.json' +echarts.registerMap('china', china) +// 引入世界地图 +import '../node_modules/echarts/map/js/world' +// 引入axios +import axios from 'axios' +Vue.prototype.$axios = axios + +import request from '../src/utils/request' +Vue.prototype.$login = request.login +Vue.prototype.$post = request.post +Vue.prototype.$get = request.get + +import App from './App' +import store from './store' +import router from './router/routers' + +import './assets/icons' // icon +import './router/index' // permission control +import 'echarts-gl' + +Vue.use(checkPer) +Vue.use(VueHighlightJS) +Vue.use(mavonEditor) +Vue.use(permission) +Vue.use(dict) +Vue.use(Element, { + size: Cookies.get('size') || 'small' // set element-ui default size +}) + +Vue.config.productionTip = false + +Vue.use(Element, { + size: Cookies.get('size') || 'medium', // set element-ui default size + i18n: (key, value) => i18n.t(key, value) +}) + +new Vue({ + el: '#app', + router, + store, + i18n, + render: h => h(App) +}) diff --git a/UI source code/dns_mapping_ui-master/src/mixins/crud.js b/UI source code/dns_mapping_ui-master/src/mixins/crud.js new file mode 100644 index 0000000..bb90342 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/mixins/crud.js @@ -0,0 +1,335 @@ +import { + initData, + download +} from '@/api/data' +import { + parseTime, + downloadFile +} from '@/utils/index' + +export default { + data() { + return { + // 表格数据 + data: [], + // 排序规则,默认 id 降序, 支持多字段排序 ['id,desc', 'createTime,asc'] + sort: ['id,desc'], + // 页码 + page: 0, + // 每页数据条数 + size: 10, + // 总数据条数 + total: 0, + // 请求数据的url + url: '', + // 查询数据的参数 + params: {}, + // 待查询的对象 + query: {}, + // 等待时间 + time: 50, + // 是否为新增类型的表单 + isAdd: false, + // 导出的 Loading + downloadLoading: false, + // 表格 Loading 属性 + loading: true, + // 删除 Loading 属性 + delLoading: false, + delAllLoading: false, + // 弹窗属性 + dialog: false, + // Form 表单 + form: {}, + // 重置表单 + resetForm: {}, + // 标题 + title: '' + } + }, + methods: { + parseTime, + downloadFile, + async init() { + if (!await this.beforeInit()) { + return + } + return new Promise((resolve, reject) => { + this.loading = true + // 请求数据 + initData(this.url, this.getQueryParame()).then(data => { + this.total = data.totalElements + this.data = data.content + // time 毫秒后显示表格 + setTimeout(() => { + this.loading = false + }, this.time) + resolve(data) + }).catch(err => { + this.loading = false + reject(err) + }) + }) + }, + beforeInit() { + return true + }, + getQueryParame: function() { + return { + page: this.page, + size: this.size, + sort: this.sort, + ...this.query, + ...this.params + } + }, + // 改变页码 + pageChange(e) { + this.page = e - 1 + this.init() + }, + // 改变每页显示数 + sizeChange(e) { + this.page = 0 + this.size = e + this.init() + }, + // 预防删除第二页最后一条数据时,或者多选删除第二页的数据时,页码错误导致请求无数据 + dleChangePage(size) { + if (size === undefined) { + size = 1 + } + if (this.data.length === size && this.page !== 0) { + this.page = this.page - 1 + } + }, + // 查询方法 + toQuery() { + this.page = 0 + this.init() + }, + /** + * 通用的提示封装 + */ + submitSuccessNotify() { + this.$notify({ + title: '提交成功', + type: 'success', + duration: 2500 + }) + }, + addSuccessNotify() { + this.$notify({ + title: '新增成功', + type: 'success', + duration: 2500 + }) + }, + editSuccessNotify() { + this.$notify({ + title: '编辑成功', + type: 'success', + duration: 2500 + }) + }, + delSuccessNotify() { + this.$notify({ + title: '删除成功', + type: 'success', + duration: 2500 + }) + }, + notify(title, type) { + this.$notify({ + title: title, + type: type, + duration: 2500 + }) + }, + /** + * 删除前可以调用 beforeDelMethod 做一些操作 + */ + beforeDelMethod() { + return true + }, + /** + * 通用的删除 + */ + delMethod(id) { + if (!this.beforeDelMethod()) { + return + } + this.delLoading = true + this.crudMethod.del(id).then(() => { + this.delLoading = false + this.$refs[id].doClose() + this.dleChangePage() + this.delSuccessNotify() + this.afterDelMethod() + this.init() + }).catch(() => { + this.delLoading = false + this.$refs[id].doClose() + }) + }, + afterDelMethod() {}, + /** + * 多选删除提示 + */ + beforeDelAllMethod() { + this.$confirm('你确定删除选中的数据吗?', '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + this.delAllMethod() + }) + }, + /** + * 多选删除 + */ + delAllMethod() { + this.delAllLoading = true + const data = this.$refs.table.selection + const ids = [] + for (let i = 0; i < data.length; i++) { + ids.push(data[i].id) + } + this.crudMethod.delAll(ids).then(() => { + this.delAllLoading = false + this.dleChangePage(ids.length) + this.init() + this.$notify({ + title: '删除成功', + type: 'success', + duration: 2500 + }) + }).catch(() => { + this.delAllLoading = false + }) + }, + /** + * 显示新增弹窗前可以调用该方法 + */ + beforeShowAddForm() {}, + /** + * 显示新增弹窗 + */ + showAddFormDialog() { + this.isAdd = true + this.resetForm = JSON.parse(JSON.stringify(this.form)) + this.beforeShowAddForm() + this.dialog = true + }, + /** + * 显示编辑弹窗前可以调用该方法 + */ + beforeShowEditForm(data) {}, + /** + * 显示编辑弹窗 + */ + showEditFormDialog(data = '') { + this.isAdd = false + if (data) { + this.resetForm = JSON.parse(JSON.stringify(this.form)) + this.form = JSON.parse(JSON.stringify(data)) + } + this.beforeShowEditForm(data) + this.dialog = true + }, + /** + * 新增方法 + */ + addMethod() { + this.crudMethod.add(this.form).then(() => { + this.addSuccessNotify() + this.loading = false + this.afterAddMethod() + this.cancel() + this.init() + }).catch(() => { + this.loading = false + this.afterAddErrorMethod() + }) + }, + /** + * 新增后可以调用该方法 + */ + afterAddMethod() {}, + /** + * 新增失败后调用该方法 + */ + afterAddErrorMethod() {}, + /** + * 通用的编辑方法 + */ + editMethod() { + this.crudMethod.edit(this.form).then(() => { + this.editSuccessNotify() + this.loading = false + this.afterEditMethod() + this.cancel() + this.init() + }).catch(() => { + this.loading = false + }) + }, + /** + * 编辑后可以调用该方法 + */ + afterEditMethod() {}, + /** + * 提交前可以调用该方法 + */ + beforeSubmitMethod() { + return true + }, + /** + * 提交 + */ + submitMethod() { + if (!this.beforeSubmitMethod()) { + return + } + if (this.$refs['form']) { + this.$refs['form'].validate((valid) => { + if (valid) { + this.loading = true + if (this.isAdd) { + this.addMethod() + } else this.editMethod() + } + }) + } + }, + /** + * 隐藏弹窗 + */ + cancel() { + this.dialog = false + if (this.$refs['form']) { + this.$refs['form'].clearValidate() + this.form = this.resetForm + } + }, + /** + * 获取弹窗的标题 + */ + getFormTitle() { + return this.isAdd ? `新增${this.title}` : `编辑${this.title}` + }, + /** + * 通用导出 + */ + downloadMethod() { + this.beforeInit() + this.downloadLoading = true + download(this.url + '/download', this.params).then(result => { + this.downloadFile(result, this.title + '数据', 'xlsx') + this.downloadLoading = false + }).catch(() => { + this.downloadLoading = false + }) + } + } +} diff --git a/UI source code/dns_mapping_ui-master/src/requst/api.js b/UI source code/dns_mapping_ui-master/src/requst/api.js new file mode 100644 index 0000000..e43e89b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/requst/api.js @@ -0,0 +1,3 @@ +import { get } from './http' + +export const getsearchList = (params) => get('http://192.168.32.6:8888/dns', params)// 搜索列表 diff --git a/UI source code/dns_mapping_ui-master/src/requst/http.js b/UI source code/dns_mapping_ui-master/src/requst/http.js new file mode 100644 index 0000000..317fbf3 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/requst/http.js @@ -0,0 +1,87 @@ +// 1.引入axios +import axios from 'axios' +import Cookies from 'js-cookie' +// 2.引入qs +import qs from 'qs' +// import router from '../router/index' + +import Vue from 'vue' +import { TokenKey } from '../settings' +// import { Toast } from "vant"; + +// Vue.use(Toast); +let baseURL = null +// process中提供了开发环境或者生产环境 +// 2.环境的切换 +if (process.env.NODE_ENV === 'development') { + // 开发环境 + baseURL = '/api' +} else if (process.env.NODE_ENV === 'production') { + // 生产环境 + baseURL = '' +} + +// 3.自定义axios请求 +const instance = axios.create({ + baseURL: baseURL, + timeout: 1000 +}) + +// 4.拦截器 +// 请求拦截器 +instance.interceptors.request.use(config => { + console.group('本次请求的地址为:' + config.url) + + if (Cookies.iskey('TokenKey')) { + if (config.url !== '/api/login') { + // const user = JSON.parse(sessionStorage.getItem('user')) + const token = Cookies.get('TokenKey') + config.headers.authorization = token + } + } + // 令牌的判断 + return config +}, err => { + // 请求失败的结果 + return Promise.reject(err) +}) + +// //响应拦截器 +instance.interceptors.response.use(res => { + // console.group('本次响应的地址为:'+res.config.url) + if (res.data.code === 403) { + // 错误消息提示 + Toast.fail(res.msg) + sessionStorage.removeItem('user') + // 路由跳转 + router.push('/login') + } + + return res +}, err => { + return Promise.reject(err) +}) + +// 封装get请求 +export function get(url, params = null) { + /** + * 1.得到Promise对象, + * 2.在实例化中需要传递一个参数,该参数是一个function + * 3.function中接受两个参数: resolve reject + * 参数一:resolve 操作成功返回的结果 + * 参数二: reject 操作失败返回的结果 + */ + return new Promise((resolve, reject) => { + // 发起真正的请求 + instance.get(url, { + params + }).then(res => { + // 返回成功的结果 + resolve(res.data) + }).catch(err => { + // 返回失败的结果 + reject(err.data) + }) + }) +} + diff --git a/UI source code/dns_mapping_ui-master/src/router/index.js b/UI source code/dns_mapping_ui-master/src/router/index.js new file mode 100644 index 0000000..47be649 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/router/index.js @@ -0,0 +1,72 @@ +import router from './routers' +import store from '@/store' +import Config from '@/settings' +import NProgress from 'nprogress' // progress bar +import 'nprogress/nprogress.css'// progress bar style +import { getToken } from '@/utils/auth' // getToken from cookie +import { buildMenus } from '@/api/system/menu' +import { filterAsyncRouter } from '@/store/modules/permission' + +NProgress.configure({ showSpinner: false })// NProgress Configuration + +const whiteList = ['/login']// no redirect whitelist + +router.beforeEach((to, from, next) => { + if (to.meta.title) { + document.title = to.meta.title + ' - ' + Config.title + } + NProgress.start() + if (getToken()) { + // 已登录且要跳转的页面是登录页 + if (to.path === '/login') { + next({ path: '/' }) + NProgress.done() + } else { + if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息 + store.dispatch('GetInfo').then(() => { // 拉取user_info + // 动态路由,拉取菜单 + loadMenus(next, to) + }).catch(() => { + store.dispatch('LogOut').then(() => { + location.reload() // 为了重新实例化vue-router对象 避免bug + }) + }) + // 登录时未拉取 菜单,在此处拉取 + } else if (store.getters.loadMenus) { + // 修改成false,防止死循环 + store.dispatch('updateLoadMenus') + loadMenus(next, to) + } else { + next() + } + } + } else { + /* has no token*/ + if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入 + next() + } else { + next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 + NProgress.done() + } + } +}) + +export const loadMenus = (next, to) => { + buildMenus().then(res => { + const sdata = JSON.parse(JSON.stringify(res)) + const rdata = JSON.parse(JSON.stringify(res)) + const sidebarRoutes = filterAsyncRouter(sdata) + const rewriteRoutes = filterAsyncRouter(rdata, false, true) + rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true }) + + store.dispatch('GenerateRoutes', rewriteRoutes).then(() => { // 存储路由 + router.addRoutes(rewriteRoutes) // 动态添加可访问路由表 + next({ ...to, replace: true }) + }) + store.dispatch('SetSidebarRouters', sidebarRoutes) + }) +} + +router.afterEach(() => { + NProgress.done() // finish progress bar +}) diff --git a/UI source code/dns_mapping_ui-master/src/router/routers.js b/UI source code/dns_mapping_ui-master/src/router/routers.js new file mode 100644 index 0000000..cdc465a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/router/routers.js @@ -0,0 +1,68 @@ +import Vue from 'vue' +import Router from 'vue-router' +import Layout from '../layout/index' + +Vue.use(Router) + +export const constantRouterMap = [ + { path: '/login', + meta: { title: '登录', noCache: true }, + component: (resolve) => require(['@/views/login'], resolve), + hidden: true + }, + { + path: '/404', + component: (resolve) => require(['@/views/features/404'], resolve), + hidden: true + }, + { + path: '/401', + component: (resolve) => require(['@/views/features/401'], resolve), + hidden: true + }, + { + path: '/redirect', + component: Layout, + hidden: true, + children: [ + { + path: '/redirect/:path*', + component: (resolve) => require(['@/views/features/redirect'], resolve) + } + ] + }, + { + path: '/', + component: Layout, + redirect: '/dashboard', + children: [ + { + path: 'dashboard', + component: (resolve) => require(['@/views/home'], resolve), + name: 'Dashboard', + meta: { title: '资源搜索', affix: true, noCache: true } + } + ] + }, + { + path: '/user', + component: Layout, + hidden: true, + redirect: 'noredirect', + children: [ + { + path: 'center', + component: (resolve) => require(['@/views/system/user/center'], resolve), + name: '个人中心', + meta: { title: '个人中心' } + } + ] + } +] + +export default new Router({ + // mode: 'hash', + mode: 'history', + scrollBehavior: () => ({ y: 0 }), + routes: constantRouterMap +}) diff --git a/UI source code/dns_mapping_ui-master/src/settings.js b/UI source code/dns_mapping_ui-master/src/settings.js new file mode 100644 index 0000000..09b49ce --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/settings.js @@ -0,0 +1,50 @@ +module.exports = { + /** + * @description 网站标题 + */ + title: 'DiamondV', + /** + * @description 是否显示 tagsView + */ + tagsView: true, + /** + * @description 固定头部 + */ + fixedHeader: true, + /** + * @description 记住密码状态下的token在Cookie中存储的天数,默认1天 + */ + tokenCookieExpires: 1, + /** + * @description 记住密码状态下的密码在Cookie中存储的天数,默认1天s + */ + passCookieExpires: 1, + /** + * @description 是否只保持一个子菜单的展开 + */ + uniqueOpened: true, + /** + * @description token key + */ + TokenKey: 'EL-ADMIN-TOEKN', + /** + * @description 请求超时时间,毫秒(默认2分钟) + */ + timeout: 1200000, + /** + * @description 是否显示logo + */ + sidebarLogo: true, + /** + * 是否显示设置的底部信息 + */ + showFooter: true, + /** + * 底部文字,支持html语法 + */ + footerTxt: '© 2019 Zheng Jie <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">Apache License 2.0</a>', + /** + * 备案号 + */ + caseNumber: '浙ICP备18005431号' +} diff --git a/UI source code/dns_mapping_ui-master/src/store/getters.js b/UI source code/dns_mapping_ui-master/src/store/getters.js new file mode 100644 index 0000000..61e650b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/store/getters.js @@ -0,0 +1,27 @@ + +const getters = { + deployUploadApi: state => state.api.deployUploadApi, + databaseUploadApi: state => state.api.databaseUploadApi, + size: state => state.app.size, + sidebar: state => state.app.sidebar, + device: state => state.app.device, + token: state => state.user.token, + visitedViews: state => state.tagsView.visitedViews, + cachedViews: state => state.tagsView.cachedViews, + roles: state => state.user.roles, + user: state => state.user.user, + loadMenus: state => state.user.loadMenus, + permission_routers: state => state.permission.routers, + addRouters: state => state.permission.addRouters, + socketApi: state => state.api.socketApi, + imagesUploadApi: state => state.api.imagesUploadApi, + baseApi: state => state.api.baseApi, + fileUploadApi: state => state.api.fileUploadApi, + updateAvatarApi: state => state.api.updateAvatarApi, + qiNiuUploadApi: state => state.api.qiNiuUploadApi, + sqlApi: state => state.api.sqlApi, + swaggerApi: state => state.api.swaggerApi, + sidebarRouters: state => state.permission.sidebarRouters, + list: state => state.searchlist.list +} +export default getters diff --git a/UI source code/dns_mapping_ui-master/src/store/index.js b/UI source code/dns_mapping_ui-master/src/store/index.js new file mode 100644 index 0000000..9954d3a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/store/index.js @@ -0,0 +1,28 @@ +import Vue from 'vue' +import Vuex from 'vuex' +import getters from './getters' + +Vue.use(Vuex) + +// https://webpack.js.org/guides/dependency-management/#requirecontext +const modulesFiles = require.context('./modules', true, /\.js$/) + +// you do not need `import app from './modules/app'` +// it will auto require all vuex module from modules file +const modules = modulesFiles.keys().reduce((modules, modulePath) => { + // set './app.js' => 'app' + const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') + const value = modulesFiles(modulePath) + modules[moduleName] = value.default + return modules +}, {}) +// import searchList from './modules/searchlist' +const store = new Vuex.Store({ + getters, + modules + // :{ + // searchList + // }, +}) + +export default store diff --git a/UI source code/dns_mapping_ui-master/src/store/modules/api.js b/UI source code/dns_mapping_ui-master/src/store/modules/api.js new file mode 100644 index 0000000..f65785e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/store/modules/api.js @@ -0,0 +1,28 @@ +// 适配 Nginx 反向代理 +const baseUrl = process.env.VUE_APP_BASE_API === '/' ? '' : process.env.VUE_APP_BASE_API +const api = { + state: { + // 部署包上传 + deployUploadApi: baseUrl + '/api/deploy/upload', + // SQL脚本上传 + databaseUploadApi: baseUrl + '/api/database/upload', + // 实时控制台 + socketApi: baseUrl + '/websocket?token=kl', + // 图片上传 + imagesUploadApi: baseUrl + '/api/localStorage/pictures', + // 修改头像 + updateAvatarApi: baseUrl + '/api/users/updateAvatar', + // 上传文件到七牛云 + qiNiuUploadApi: baseUrl + '/api/qiNiuContent', + // Sql 监控 + sqlApi: baseUrl + '/druid/index.html', + // swagger + swaggerApi: baseUrl + '/swagger-ui.html', + // 文件上传 + fileUploadApi: baseUrl + '/api/localStorage', + // baseUrl, + baseApi: baseUrl + } +} + +export default api diff --git a/UI source code/dns_mapping_ui-master/src/store/modules/app.js b/UI source code/dns_mapping_ui-master/src/store/modules/app.js new file mode 100644 index 0000000..a384479 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/store/modules/app.js @@ -0,0 +1,56 @@ +import Cookies from 'js-cookie' + +const state = { + sidebar: { + opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, + withoutAnimation: false + }, + device: 'desktop', + size: Cookies.get('size') || 'small' +} + +const mutations = { + TOGGLE_SIDEBAR: state => { + state.sidebar.opened = !state.sidebar.opened + state.sidebar.withoutAnimation = false + if (state.sidebar.opened) { + Cookies.set('sidebarStatus', 1) + } else { + Cookies.set('sidebarStatus', 0) + } + }, + CLOSE_SIDEBAR: (state, withoutAnimation) => { + Cookies.set('sidebarStatus', 0) + state.sidebar.opened = false + state.sidebar.withoutAnimation = withoutAnimation + }, + TOGGLE_DEVICE: (state, device) => { + state.device = device + }, + SET_SIZE: (state, size) => { + state.size = size + Cookies.set('size', size) + } +} + +const actions = { + toggleSideBar({ commit }) { + commit('TOGGLE_SIDEBAR') + }, + closeSideBar({ commit }, { withoutAnimation }) { + commit('CLOSE_SIDEBAR', withoutAnimation) + }, + toggleDevice({ commit }, device) { + commit('TOGGLE_DEVICE', device) + }, + setSize({ commit }, size) { + commit('SET_SIZE', size) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} diff --git a/UI source code/dns_mapping_ui-master/src/store/modules/permission.js b/UI source code/dns_mapping_ui-master/src/store/modules/permission.js new file mode 100644 index 0000000..513e259 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/store/modules/permission.js @@ -0,0 +1,83 @@ +import { constantRouterMap } from '@/router/routers' +import Layout from '@/layout/index' +import ParentView from '@/components/ParentView' + +const permission = { + state: { + routers: constantRouterMap, + addRouters: [], + sidebarRouters: [] + }, + mutations: { + SET_ROUTERS: (state, routers) => { + state.addRouters = routers + state.routers = constantRouterMap.concat(routers) + }, + SET_SIDEBAR_ROUTERS: (state, routers) => { + state.sidebarRouters = constantRouterMap.concat(routers) + } + }, + actions: { + GenerateRoutes({ commit }, asyncRouter) { + commit('SET_ROUTERS', asyncRouter) + }, + SetSidebarRouters({ commit }, sidebarRouter) { + commit('SET_SIDEBAR_ROUTERS', sidebarRouter) + } + } +} + +export const filterAsyncRouter = (routers, lastRouter = false, type = false) => { // 遍历后台传来的路由字符串,转换为组件对象 + return routers.filter(router => { + if (type && router.children) { + router.children = filterChildren(router.children) + } + if (router.component) { + if (router.component === 'Layout') { // Layout组件特殊处理 + router.component = Layout + } else if (router.component === 'ParentView') { + router.component = ParentView + } else { + const component = router.component + router.component = loadView(component) + } + } + if (router.children != null && router.children && router.children.length) { + router.children = filterAsyncRouter(router.children, router, type) + } else { + delete router['children'] + delete router['redirect'] + } + return true + }) +} + +function filterChildren(childrenMap, lastRouter = false) { + var children = [] + childrenMap.forEach((el, index) => { + if (el.children && el.children.length) { + if (el.component === 'ParentView') { + el.children.forEach(c => { + c.path = el.path + '/' + c.path + if (c.children && c.children.length) { + children = children.concat(filterChildren(c.children, c)) + return + } + children.push(c) + }) + return + } + } + if (lastRouter) { + el.path = lastRouter.path + '/' + el.path + } + children = children.concat(el) + }) + return children +} + +export const loadView = (view) => { + return (resolve) => require([`@/views/${view}`], resolve) +} + +export default permission diff --git a/UI source code/dns_mapping_ui-master/src/store/modules/searchlist.js b/UI source code/dns_mapping_ui-master/src/store/modules/searchlist.js new file mode 100644 index 0000000..f083461 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/store/modules/searchlist.js @@ -0,0 +1,131 @@ +import { getsearchList, getleftList, getmapList } from '../../api/search' + +const state = { + list: [], // 搜索列表 + size: 10, // 每页多少条数据 + page: 1, // 当前第几页 + pages: 1, // 一共多少页 + resultTotal: 6, // 共多少条数据,分页 + left: [], // 左侧列表 + maplist: [], + Loging:true, +} + +const mutations = { + changeList(state, arr) { + state.list = arr + console.log(state.list, 222) + }, + changeLoging(state,loging){ + state.Loging = loging + // console.log(state.Loging,111); + }, + // 改变右侧列表 + changeLeft(state, left) { + state.left = left + // console.log(state.left, 333) + }, + // 地图 + changeMaplist(state, map) { + state.maplist = map + // console.log(state.maplist, 444) + }, + // 改变页数 + changePage(state, page) { + state.page = page + }, + // 改变每页请求条数 + changeSize(state, size) { + state.size = size + } +} + +const actions = { + listActions(context, obj) { + + const params = { + ip: obj.ip ? obj.ip :"", + port: obj.port ? obj.port : "", + service: obj.service ? obj.service : "", + size: state.size, + page: state.page + } + getsearchList(params).then(res => { + // console.log(params,555); + if (res.status === 200) { + if ((res.data.list === null || res.data.list.length === 0) && state.page > 1) { + // console.log(456); + const page = state.page - 1 + context.commit('changePage', page) + context.dispatch('listActions') + return + } + // console.log(res,"res"); + context.commit('changeList', res.data) + context.commit('changeLoging',false) + } + }).catch(() => console.log('列表请求未执行')) + }, + // 左侧列表请求 + leftlistActions(context, obj) { + const params = { + ip: obj.ip, + port: obj.port, + service: obj.service + } + // console.log(params); + getleftList(params).then(res => { + if (res.status === 200) { + context.commit('changeLeft', res.data) + } + }).catch(() => console.log('左侧列表请求未执行')) + }, + // 地图请求 + maplistActions(context) { + getmapList().then(res => { + // console.log(res.data); + if (res.status === 200) { + context.commit('changeMaplist', res.data) + } + }).catch(() => console.log('地图请求未执行')) + }, + // 修改当前页码数 + pageActions(context, page) { + context.commit('changePage', page) + }, + // 修改每页请求条数 + sizeActions(context, size) { + context.commit('changeSize', size) + } +} +// 派生状态 +const getters = { + // 系统自动注入参数state + list(state) { + return state.list + }, + left(state) { + return state.left + }, + maplist(state) { + return state.maplist + }, + size(state) { + return state.size + }, + total(state) { + return state.resultTotal + }, + Loging(state){ + return state.Loging + } +} + +// 导出 +export default { + state, + mutations, + actions, + getters, + namespaced: true// 使用命名空间 +} diff --git a/UI source code/dns_mapping_ui-master/src/store/modules/settings.js b/UI source code/dns_mapping_ui-master/src/store/modules/settings.js new file mode 100644 index 0000000..715ef48 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/store/modules/settings.js @@ -0,0 +1,38 @@ +import variables from '@/assets/styles/element-variables.scss' +import defaultSettings from '@/settings' +const { tagsView, fixedHeader, sidebarLogo, uniqueOpened, showFooter, footerTxt, caseNumber, menuInLeft } = defaultSettings + +const state = { + theme: variables.theme, + showSettings: false, + tagsView: tagsView, + fixedHeader: fixedHeader, + sidebarLogo: sidebarLogo, + uniqueOpened: uniqueOpened, + showFooter: showFooter, + footerTxt: footerTxt, + caseNumber: caseNumber, + menuInLeft: false +} + +const mutations = { + CHANGE_SETTING: (state, { key, value }) => { + if (state.hasOwnProperty(key)) { + state[key] = value + } + } +} + +const actions = { + changeSetting({ commit }, data) { + commit('CHANGE_SETTING', data) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} + diff --git a/UI source code/dns_mapping_ui-master/src/store/modules/tagsView.js b/UI source code/dns_mapping_ui-master/src/store/modules/tagsView.js new file mode 100644 index 0000000..3e2c170 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/store/modules/tagsView.js @@ -0,0 +1,165 @@ +const state = { + visitedViews: [], + cachedViews: [] +} + +const mutations = { + ADD_VISITED_VIEW: (state, view) => { + if (state.visitedViews.some(v => v.path === view.path)) return + state.visitedViews.push( + Object.assign({}, view, { + title: view.meta.title || 'no-name' + }) + ) + }, + ADD_CACHED_VIEW: (state, view) => { + if (state.cachedViews.includes(view.name)) return + if (!view.meta.noCache) { + state.cachedViews.push(view.name) + } + }, + + DEL_VISITED_VIEW: (state, view) => { + for (const [i, v] of state.visitedViews.entries()) { + if (v.path === view.path) { + state.visitedViews.splice(i, 1) + break + } + } + }, + DEL_CACHED_VIEW: (state, view) => { + for (const i of state.cachedViews) { + if (i === view.name) { + const index = state.cachedViews.indexOf(i) + state.cachedViews.splice(index, 1) + break + } + } + }, + + DEL_OTHERS_VISITED_VIEWS: (state, view) => { + state.visitedViews = state.visitedViews.filter(v => { + return v.meta.affix || v.path === view.path + }) + }, + DEL_OTHERS_CACHED_VIEWS: (state, view) => { + for (const i of state.cachedViews) { + if (i === view.name) { + const index = state.cachedViews.indexOf(i) + state.cachedViews = state.cachedViews.slice(index, index + 1) + break + } + } + }, + + DEL_ALL_VISITED_VIEWS: state => { + // keep affix tags + const affixTags = state.visitedViews.filter(tag => tag.meta.affix) + state.visitedViews = affixTags + }, + DEL_ALL_CACHED_VIEWS: state => { + state.cachedViews = [] + }, + + UPDATE_VISITED_VIEW: (state, view) => { + for (let v of state.visitedViews) { + if (v.path === view.path) { + v = Object.assign(v, view) + break + } + } + } +} + +const actions = { + addView({ dispatch }, view) { + dispatch('addVisitedView', view) + dispatch('addCachedView', view) + }, + addVisitedView({ commit }, view) { + commit('ADD_VISITED_VIEW', view) + }, + addCachedView({ commit }, view) { + commit('ADD_CACHED_VIEW', view) + }, + + delView({ dispatch, state }, view) { + return new Promise(resolve => { + dispatch('delVisitedView', view) + dispatch('delCachedView', view) + resolve({ + visitedViews: [...state.visitedViews], + cachedViews: [...state.cachedViews] + }) + }) + }, + delVisitedView({ commit, state }, view) { + return new Promise(resolve => { + commit('DEL_VISITED_VIEW', view) + resolve([...state.visitedViews]) + }) + }, + delCachedView({ commit, state }, view) { + return new Promise(resolve => { + commit('DEL_CACHED_VIEW', view) + resolve([...state.cachedViews]) + }) + }, + + delOthersViews({ dispatch, state }, view) { + return new Promise(resolve => { + dispatch('delOthersVisitedViews', view) + dispatch('delOthersCachedViews', view) + resolve({ + visitedViews: [...state.visitedViews], + cachedViews: [...state.cachedViews] + }) + }) + }, + delOthersVisitedViews({ commit, state }, view) { + return new Promise(resolve => { + commit('DEL_OTHERS_VISITED_VIEWS', view) + resolve([...state.visitedViews]) + }) + }, + delOthersCachedViews({ commit, state }, view) { + return new Promise(resolve => { + commit('DEL_OTHERS_CACHED_VIEWS', view) + resolve([...state.cachedViews]) + }) + }, + + delAllViews({ dispatch, state }, view) { + return new Promise(resolve => { + dispatch('delAllVisitedViews', view) + dispatch('delAllCachedViews', view) + resolve({ + visitedViews: [...state.visitedViews], + cachedViews: [...state.cachedViews] + }) + }) + }, + delAllVisitedViews({ commit, state }) { + return new Promise(resolve => { + commit('DEL_ALL_VISITED_VIEWS') + resolve([...state.visitedViews]) + }) + }, + delAllCachedViews({ commit, state }) { + return new Promise(resolve => { + commit('DEL_ALL_CACHED_VIEWS') + resolve([...state.cachedViews]) + }) + }, + + updateVisitedView({ commit }, view) { + commit('UPDATE_VISITED_VIEW', view) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} diff --git a/UI source code/dns_mapping_ui-master/src/store/modules/user.js b/UI source code/dns_mapping_ui-master/src/store/modules/user.js new file mode 100644 index 0000000..3b1c7fb --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/store/modules/user.js @@ -0,0 +1,94 @@ +import { login, getInfo, logout } from '@/api/login' +import { getToken, setToken, removeToken } from '@/utils/auth' + +const user = { + state: { + token: getToken(), + user: {}, + roles: [], + // 第一次加载菜单时用到 + loadMenus: false + }, + + mutations: { + SET_TOKEN: (state, token) => { + state.token = token + }, + SET_USER: (state, user) => { + state.user = user + }, + SET_ROLES: (state, roles) => { + state.roles = roles + }, + SET_LOAD_MENUS: (state, loadMenus) => { + state.loadMenus = loadMenus + } + }, + + actions: { + // 登录 + Login({ commit }, userInfo) { + const rememberMe = userInfo.rememberMe + return new Promise((resolve, reject) => { + login(userInfo.username, userInfo.password, userInfo.code, userInfo.uuid).then(res => { + setToken(res.token, rememberMe) + commit('SET_TOKEN', res.token) + setUserInfo(res.user, commit) + // 第一次加载菜单时用到, 具体见 src 目录下的 permission.js + commit('SET_LOAD_MENUS', true) + resolve() + }).catch(error => { + reject(error) + }) + }) + }, + + // 获取用户信息 + GetInfo({ commit }) { + return new Promise((resolve, reject) => { + getInfo().then(res => { + setUserInfo(res, commit) + resolve(res) + }).catch(error => { + reject(error) + }) + }) + }, + // 登出 + LogOut({ commit }) { + return new Promise((resolve, reject) => { + logout().then(res => { + logOut(commit) + resolve() + }).catch(error => { + logOut(commit) + reject(error) + }) + }) + }, + + updateLoadMenus({ commit }) { + return new Promise((resolve, reject) => { + commit('SET_LOAD_MENUS', false) + }) + } + } +} + +export const logOut = (commit) => { + commit('SET_TOKEN', '') + commit('SET_ROLES', []) + removeToken() +} + +export const setUserInfo = (res, commit) => { + // 如果没有任何权限,则赋予一个默认的权限,避免请求死循环 + if (res.roles.length === 0) { + commit('SET_ROLES', ['ROLE_SYSTEM_DEFAULT']) + } else { + commit('SET_ROLES', res.roles) + } + commit('SET_USER', res.user) +} + +export default user diff --git a/UI source code/dns_mapping_ui-master/src/utils/auth.js b/UI source code/dns_mapping_ui-master/src/utils/auth.js new file mode 100644 index 0000000..b643e73 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/auth.js @@ -0,0 +1,18 @@ +import Cookies from 'js-cookie' +import Config from '@/settings' + +const TokenKey = Config.TokenKey + +export function getToken() { + return Cookies.get(TokenKey) +} + +export function setToken(token, rememberMe) { + if (rememberMe) { + return Cookies.set(TokenKey, token, { expires: Config.tokenCookieExpires }) + } else return Cookies.set(TokenKey, token) +} + +export function removeToken() { + return Cookies.remove(TokenKey) +} diff --git a/UI source code/dns_mapping_ui-master/src/utils/chinamap.js b/UI source code/dns_mapping_ui-master/src/utils/chinamap.js new file mode 100644 index 0000000..0718c33 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/chinamap.js @@ -0,0 +1,491 @@ +const chinaGeoCoordMap = { + 六安: [116.3123, 31.8329], + 安庆: [116.7517, 30.5255], + 滁州: [118.1909, 32.536], + 宣城: [118.8062, 30.6244], + 阜阳: [115.7629, 32.9919], + 宿州: [117.5208, 33.6841], + 黄山: [118.0481, 29.9542], + 巢湖: [117.7734, 31.4978], + 亳州: [116.1914, 33.4698], + 池州: [117.3889, 30.2014], + 合肥: [117.29, 32.0581], + 蚌埠: [117.4109, 33.1073], + 芜湖: [118.3557, 31.0858], + 淮北: [116.6968, 33.6896], + 淮南: [116.7847, 32.7722], + 马鞍山: [118.6304, 31.5363], + 铜陵: [117.9382, 30.9375], + 澳门: [113.5547, 22.1484], + 密云县: [117.0923, 40.5121], + 怀柔区: [116.6377, 40.6219], + 房山区: [115.8453, 39.7163], + 延庆县: [116.1543, 40.5286], + 门头沟区: [115.8, 39.9957], + 昌平区: [116.1777, 40.2134], + 大兴区: [116.4716, 39.6352], + 顺义区: [116.7242, 40.1619], + 平谷区: [117.1706, 40.2052], + 通州区: [116.7297, 39.8131], + 朝阳区: [116.4977, 39.949], + 海淀区: [116.2202, 40.0239], + 丰台区: [116.2683, 39.8309], + 石景山区: [116.1887, 39.9346], + 西城区: [116.3631, 39.9353], + 东城区: [116.418, 39.9367], + 宣武区: [116.3603, 39.8852], + 崇文区: [116.4166, 39.8811], + 新疆: [84.9023, 41.748], + 西藏: [88.7695, 31.6846], + 内蒙古: [117.5977, 44.3408], + 青海: [96.2402, 35.4199], + 四川: [102.9199, 30.1904], + 黑龙江: [128.1445, 48.5156], + 甘肃: [95.7129, 40.166], + 云南: [101.8652, 25.1807], + 广西: [108.2813, 23.6426], + 湖南: [111.5332, 27.3779], + 陕西: [109.5996, 35.6396], + 广东: [113.4668, 22.8076], + 吉林: [126.4746, 43.5938], + 河北: [115.4004, 37.9688], + 湖北: [112.2363, 31.1572], + 贵州: [106.6113, 26.9385], + 山东: [118.7402, 36.4307], + 江西: [116.0156, 27.29], + 河南: [113.4668, 33.8818], + 辽宁: [122.3438, 41.0889], + 山西: [112.4121, 37.6611], + 安徽: [117.2461, 32.0361], + 福建: [118.3008, 25.9277], + 浙江: [120.498, 29.0918], + 江苏: [120.0586, 32.915], + 重庆: [107.7539, 30.1904], + 宁夏: [105.9961, 37.3096], + 海南: [109.9512, 19.2041], + 台湾: [121.0295, 23.6082], + 北京: [116.4551, 40.2539], + 天津: [117.4219, 39.4189], + 上海: [121.4648, 31.2891], + 香港: [114.2784, 22.3057], + 酉阳土家族苗族自治县: [108.8196, 28.8666], + 奉节县: [109.3909, 30.9265], + 巫溪县: [109.3359, 31.4813], + 开县: [108.4131, 31.2561], + 彭水苗族土家族自治县: [108.2043, 29.3994], + 云阳县: [108.8306, 31.0089], + 万州区: [108.3911, 30.6958], + 城口县: [108.7756, 31.9098], + 江津区: [106.2158, 28.9874], + 石柱土家族自治县: [108.2813, 30.1025], + 巫山县: [109.8853, 31.1188], + 涪陵区: [107.3364, 29.6796], + 丰都县: [107.8418, 29.9048], + 武隆县: [107.655, 29.35], + 南川区: [107.1716, 29.1302], + 秀山土家族苗族自治县: [109.0173, 28.5205], + 黔江区: [108.7207, 29.4708], + 合川区: [106.3257, 30.108], + 綦江县: [106.6553, 28.8171], + 忠县: [107.8967, 30.3223], + 梁平县: [107.7429, 30.6519], + 巴南区: [106.7322, 29.4214], + 潼南县: [105.7764, 30.1135], + 永川区: [105.8643, 29.2566], + 垫江县: [107.4573, 30.2454], + 渝北区: [106.7212, 29.8499], + 长寿区: [107.1606, 29.9762], + 大足县: [105.7544, 29.6136], + 铜梁县: [106.0291, 29.8059], + 荣昌县: [105.5127, 29.4708], + 璧山县: [106.2048, 29.5807], + 北碚区: [106.5674, 29.8883], + 万盛区: [106.908, 28.9325], + 九龙坡区: [106.3586, 29.4049], + 沙坪坝区: [106.3696, 29.6191], + 南岸区: [106.6663, 29.5367], + 江北区: [106.8311, 29.6191], + 大渡口区: [106.4905, 29.4214], + 双桥区: [105.7874, 29.4928], + 渝中区: [106.5344, 29.5477], + 南平: [118.136, 27.2845], + 三明: [117.5317, 26.3013], + 龙岩: [116.8066, 25.2026], + 宁德: [119.6521, 26.9824], + 福州: [119.4543, 25.9222], + 漳州: [117.5757, 24.3732], + 泉州: [118.3228, 25.1147], + 莆田: [119.0918, 25.3455], + 厦门: [118.1689, 24.6478], + 酒泉: [96.2622, 40.4517], + 张掖: [99.7998, 38.7433], + 甘南藏族自治州: [102.9199, 34.6893], + 武威: [103.0188, 38.1061], + 陇南: [105.304, 33.5632], + 庆阳: [107.5342, 36.2], + 白银: [104.8645, 36.5076], + 定西: [104.5569, 35.0848], + 天水: [105.6445, 34.6289], + 兰州: [103.5901, 36.3043], + 平凉: [107.0728, 35.321], + 临夏回族自治州: [103.2715, 35.5737], + 金昌: [102.074, 38.5126], + 嘉峪关: [98.1738, 39.8035], + 清远: [112.9175, 24.3292], + 韶关: [113.7964, 24.7028], + 湛江: [110.3577, 20.9894], + 梅州: [116.1255, 24.1534], + 河源: [114.917, 23.9722], + 肇庆: [112.1265, 23.5822], + 惠州: [114.6204, 23.1647], + 茂名: [111.0059, 22.0221], + 江门: [112.6318, 22.1484], + 阳江: [111.8298, 22.0715], + 云浮: [111.7859, 22.8516], + 广州: [113.5107, 23.2196], + 汕尾: [115.5762, 23.0438], + 揭阳: [116.1255, 23.313], + 珠海: [113.7305, 22.1155], + 佛山: [112.8955, 23.1097], + 潮州: [116.7847, 23.8293], + 汕头: [117.1692, 23.3405], + 深圳: [114.5435, 22.5439], + 东莞: [113.8953, 22.901], + 中山: [113.4229, 22.478], + 百色: [106.6003, 23.9227], + 河池: [107.8638, 24.5819], + 桂林: [110.5554, 25.318], + 南宁: [108.479, 23.1152], + 柳州: [109.3799, 24.9774], + 崇左: [107.3364, 22.4725], + 来宾: [109.7095, 23.8403], + 玉林: [110.2148, 22.3792], + 梧州: [110.9949, 23.5052], + 贺州: [111.3135, 24.4006], + 钦州: [109.0283, 22.0935], + 贵港: [109.9402, 23.3459], + 防城港: [108.0505, 21.9287], + 北海: [109.314, 21.6211], + 遵义: [106.908, 28.1744], + 黔东南苗族侗族自治州: [108.4241, 26.4166], + 毕节地区: [105.1611, 27.0648], + 黔南布依族苗族自治州: [107.2485, 25.8398], + 铜仁地区: [108.6218, 28.0096], + 黔西南布依族苗族自治州: [105.5347, 25.3949], + 六盘水: [104.7546, 26.0925], + 安顺: [105.9082, 25.9882], + 贵阳: [106.6992, 26.7682], + 儋州: [109.3291, 19.5653], + 文昌: [110.8905, 19.7823], + 乐东黎族自治县: [109.0283, 18.6301], + 三亚: [109.3716, 18.3698], + 琼中黎族苗族自治县: [109.8413, 19.0736], + 东方: [108.8498, 19.0414], + 海口: [110.3893, 19.8516], + 万宁: [110.3137, 18.8388], + 澄迈县: [109.9937, 19.7314], + 白沙黎族自治县: [109.3703, 19.211], + 琼海: [110.4208, 19.224], + 昌江黎族自治县: [109.0407, 19.2137], + 临高县: [109.6957, 19.8063], + 陵水黎族自治县: [109.9924, 18.5415], + 屯昌县: [110.0377, 19.362], + 定安县: [110.3384, 19.4698], + 保亭黎族苗族自治县: [109.6284, 18.6108], + 五指山: [109.5282, 18.8299], + 黑河: [127.1448, 49.2957], + 大兴安岭地区: [124.1016, 52.2345], + 哈尔滨: [127.9688, 45.368], + 齐齐哈尔: [124.541, 47.5818], + 牡丹江: [129.7815, 44.7089], + 绥化: [126.7163, 46.8018], + 伊春: [129.1992, 47.9608], + 佳木斯: [133.0005, 47.5763], + 鸡西: [132.7917, 45.7361], + 双鸭山: [133.5938, 46.7523], + 大庆: [124.7717, 46.4282], + 鹤岗: [130.4407, 47.7081], + 七台河: [131.2756, 45.9558], + 承德: [117.5757, 41.4075], + 张家口: [115.1477, 40.8527], + 保定: [115.0488, 39.0948], + 唐山: [118.4766, 39.6826], + 沧州: [116.8286, 38.2104], + 石家庄: [114.4995, 38.1006], + 邢台: [114.8071, 37.2821], + 邯郸: [114.4775, 36.535], + 秦皇岛: [119.2126, 40.0232], + 衡水: [115.8838, 37.7161], + 廊坊: [116.521, 39.0509], + 南阳: [112.4011, 33.0359], + 信阳: [114.8291, 32.0197], + 洛阳: [112.0605, 34.3158], + 驻马店: [114.1589, 32.9041], + 周口: [114.873, 33.6951], + 商丘: [115.741, 34.2828], + 三门峡: [110.8301, 34.3158], + 新乡: [114.2029, 35.3595], + 平顶山: [112.9724, 33.739], + 郑州: [113.4668, 34.6234], + 安阳: [114.5325, 36.0022], + 开封: [114.5764, 34.6124], + 焦作: [112.8406, 35.1508], + 许昌: [113.6975, 34.0466], + 濮阳: [115.1917, 35.799], + 漯河: [113.8733, 33.6951], + 鹤壁: [114.3787, 35.744], + 怀化: [109.9512, 27.4438], + 永州: [111.709, 25.752], + 邵阳: [110.9619, 26.8121], + 郴州: [113.2361, 25.8673], + 常德: [111.4014, 29.2676], + 湘西土家族苗族自治州: [109.7864, 28.6743], + 衡阳: [112.4121, 26.7902], + 岳阳: [113.2361, 29.1357], + 益阳: [111.731, 28.3832], + 长沙: [113.0823, 28.2568], + 株洲: [113.5327, 27.0319], + 张家界: [110.5115, 29.328], + 娄底: [111.6431, 27.7185], + 湘潭: [112.5439, 27.7075], + 盐城: [120.2234, 33.5577], + 徐州: [117.5208, 34.3268], + 南通: [121.1023, 32.1625], + 淮安: [118.927, 33.4039], + 苏州: [120.6519, 31.3989], + 宿迁: [118.5535, 33.7775], + 连云港: [119.1248, 34.552], + 扬州: [119.4653, 32.8162], + 南京: [118.8062, 31.9208], + 泰州: [120.0586, 32.5525], + 无锡: [120.3442, 31.5527], + 常州: [119.4543, 31.5582], + 镇江: [119.4763, 31.9702], + 赣州: [115.2795, 25.8124], + 吉安: [114.884, 26.9659], + 上饶: [117.8613, 28.7292], + 九江: [115.4224, 29.3774], + 抚州: [116.4441, 27.4933], + 宜春: [115.0159, 28.3228], + 南昌: [116.0046, 28.6633], + 景德镇: [117.334, 29.3225], + 萍乡: [113.9282, 27.4823], + 鹰潭: [117.0813, 28.2349], + 新余: [114.95, 27.8174], + 延边朝鲜族自治州: [129.397, 43.2587], + 白城: [123.0029, 45.2637], + 松原: [124.0906, 44.7198], + 长春: [125.8154, 44.2584], + 白山: [127.2217, 42.0941], + 通化: [125.9583, 41.8579], + 四平: [124.541, 43.4894], + 辽源: [125.343, 42.7643], + 大连: [122.2229, 39.4409], + 朝阳: [120.0696, 41.4899], + 丹东: [124.541, 40.4242], + 铁岭: [124.2773, 42.7423], + 沈阳: [123.1238, 42.1216], + 抚顺: [124.585, 41.8579], + 葫芦岛: [120.1575, 40.578], + 阜新: [122.0032, 42.2699], + 锦州: [121.6626, 41.4294], + 鞍山: [123.0798, 40.6055], + 本溪: [124.1455, 41.1987], + 营口: [122.4316, 40.4297], + 辽阳: [123.4094, 41.1383], + 盘锦: [121.9482, 41.0449], + 呼伦贝尔: [120.8057, 50.2185], + 阿拉善盟: [102.019, 40.1001], + 锡林郭勒盟: [115.6421, 44.176], + 鄂尔多斯: [108.9734, 39.2487], + 赤峰: [118.6743, 43.2642], + 巴彦淖尔: [107.5562, 41.3196], + 通辽: [121.4758, 43.9673], + 乌兰察布: [112.5769, 41.77], + 兴安盟: [121.3879, 46.1426], + 包头: [110.3467, 41.4899], + 呼和浩特: [111.4124, 40.4901], + 乌海: [106.886, 39.4739], + 吴忠: [106.853, 37.3755], + 中卫: [105.4028, 36.9525], + 固原: [106.1389, 35.9363], + 银川: [106.3586, 38.1775], + 石嘴山: [106.4795, 39.0015], + 海西蒙古族藏族自治州: [94.9768, 37.1118], + 玉树藏族自治州: [93.5925, 33.9368], + 果洛藏族自治州: [99.3823, 34.0466], + 海南藏族自治州: [100.3711, 35.9418], + 海北藏族自治州: [100.3711, 37.9138], + 黄南藏族自治州: [101.5686, 35.1178], + 海东地区: [102.3706, 36.2988], + 西宁: [101.4038, 36.8207], + 崇明县: [121.5637, 31.5383], + 南汇区: [121.8755, 30.954], + 奉贤区: [121.5747, 30.8475], + 浦东新区: [121.6928, 31.2561], + 金山区: [121.2657, 30.8112], + 青浦区: [121.1751, 31.1909], + 松江区: [121.1984, 31.0268], + 嘉定区: [121.2437, 31.3625], + 宝山区: [121.4346, 31.4051], + 闵行区: [121.4992, 31.0838], + 杨浦区: [121.528, 31.2966], + 普陀区: [121.3879, 31.2602], + 徐汇区: [121.4333, 31.1607], + 长宁区: [121.3852, 31.2115], + 闸北区: [121.4511, 31.2794], + 虹口区: [121.4882, 31.2788], + 黄浦区: [121.4868, 31.219], + 卢湾区: [121.4758, 31.2074], + 静安区: [121.4484, 31.2286], + 榆林: [109.8743, 38.205], + 延安: [109.1052, 36.4252], + 汉中: [106.886, 33.0139], + 安康: [109.1162, 32.7722], + 商洛: [109.8083, 33.761], + 宝鸡: [107.1826, 34.3433], + 渭南: [109.7864, 35.0299], + 咸阳: [108.4131, 34.8706], + 西安: [109.1162, 34.2004], + 铜川: [109.0393, 35.1947], + 忻州: [112.4561, 38.8971], + 吕梁: [111.3574, 37.7325], + 临汾: [111.4783, 36.1615], + 晋中: [112.7747, 37.37], + 运城: [111.1487, 35.2002], + 大同: [113.7854, 39.8035], + 长治: [112.8625, 36.4746], + 朔州: [113.0713, 39.6991], + 晋城: [112.7856, 35.6342], + 太原: [112.3352, 37.9413], + 阳泉: [113.4778, 38.0951], + 甘孜藏族自治州: [99.9207, 31.0803], + 阿坝藏族羌族自治州: [102.4805, 32.4536], + 凉山彝族自治州: [101.9641, 27.6746], + 绵阳: [104.7327, 31.8713], + 达州: [107.6111, 31.333], + 广元: [105.6885, 32.2284], + 雅安: [102.6672, 29.8938], + 宜宾: [104.6558, 28.548], + 乐山: [103.5791, 29.1742], + 南充: [106.2048, 31.1517], + 巴中: [107.0618, 31.9977], + 泸州: [105.4578, 28.493], + 成都: [103.9526, 30.7617], + 资阳: [104.9744, 30.1575], + 攀枝花: [101.6895, 26.7133], + 眉山: [103.8098, 30.0146], + 广安: [106.6333, 30.4376], + 德阳: [104.48, 31.1133], + 内江: [104.8535, 29.6136], + 遂宁: [105.5347, 30.6683], + 自贡: [104.6667, 29.2786], + 蓟县: [117.4672, 40.004], + 武清区: [117.0621, 39.4121], + 宝坻区: [117.4274, 39.5913], + 静海县: [116.9824, 38.8312], + 宁河县: [117.6801, 39.3853], + 大港区: [117.3875, 38.757], + 塘沽区: [117.6801, 38.9987], + 西青区: [117.1829, 39.0022], + 北辰区: [117.1761, 39.2548], + 东丽区: [117.4013, 39.1223], + 汉沽区: [117.8888, 39.2191], + 津南区: [117.3958, 38.9603], + 河西区: [117.2365, 39.0804], + 河东区: [117.2571, 39.1209], + 南开区: [117.1527, 39.1065], + 河北区: [117.2145, 39.1615], + 红桥区: [117.1596, 39.1663], + 和平区: [117.2008, 39.1189], + 巴音郭楞蒙古自治州: [88.1653, 39.6002], + 和田地区: [81.167, 36.9855], + 哈密地区: [93.7793, 42.9236], + 阿克苏地区: [82.9797, 41.0229], + 阿勒泰地区: [88.2971, 47.0929], + 喀什地区: [77.168, 37.8534], + 塔城地区: [86.6272, 45.8514], + 昌吉回族自治州: [89.6814, 44.4507], + 克孜勒苏柯尔克孜自治州: [74.6301, 39.5233], + 吐鲁番地区: [89.6375, 42.4127], + 伊犁哈萨克自治州: [82.5513, 43.5498], + 博尔塔拉蒙古自治州: [81.8481, 44.6979], + 乌鲁木齐: [87.9236, 43.5883], + 克拉玛依: [85.2869, 45.5054], + 阿拉尔: [81.2769, 40.6549], + 图木舒克: [79.1345, 39.8749], + 五家渠: [87.5391, 44.3024], + 石河子: [86.0229, 44.2914], + 那曲地区: [88.1982, 33.3215], + 阿里地区: [82.3645, 32.7667], + 日喀则地区: [86.2427, 29.5093], + 林芝地区: [95.4602, 29.1138], + 昌都地区: [97.0203, 30.7068], + 山南地区: [92.2083, 28.3392], + 拉萨: [91.1865, 30.1465], + 普洱: [100.7446, 23.4229], + 红河哈尼族彝族自治州: [103.0408, 23.6041], + 文山壮族苗族自治州: [104.8865, 23.5712], + 曲靖: [103.9417, 25.7025], + 楚雄彝族自治州: [101.6016, 25.3619], + 大理白族自治州: [99.9536, 25.6805], + 临沧: [99.613, 24.0546], + 迪庆藏族自治州: [99.4592, 27.9327], + 昭通: [104.0955, 27.6031], + 昆明: [102.9199, 25.4663], + 丽江: [100.448, 26.955], + 西双版纳傣族自治州: [100.8984, 21.8628], + 保山: [99.0637, 24.9884], + 玉溪: [101.9312, 23.8898], + 怒江傈僳族自治州: [99.1516, 26.5594], + 德宏傣族景颇族自治州: [98.1299, 24.5874], + 丽水: [119.5642, 28.1854], + 杭州: [119.5313, 29.8773], + 温州: [120.498, 27.8119], + 宁波: [121.5967, 29.6466], + 舟山: [122.2559, 30.2234], + 台州: [121.1353, 28.6688], + 金华: [120.0037, 29.1028], + 衢州: [118.6853, 28.8666], + 绍兴: [120.564, 29.7565], + 嘉兴: [120.9155, 30.6354], + 湖州: [119.8608, 30.7782], + 烟台: [120.7397, 37.5128], + 临沂: [118.3118, 35.2936], + 潍坊: [119.0918, 36.524], + 青岛: [120.4651, 36.3373], + 菏泽: [115.6201, 35.2057], + 济宁: [116.8286, 35.3375], + 德州: [116.6858, 37.2107], + 滨州: [117.8174, 37.4963], + 聊城: [115.9167, 36.4032], + 东营: [118.7073, 37.5513], + 济南: [117.1582, 36.8701], + 泰安: [117.0264, 36.0516], + 威海: [121.9482, 37.1393], + 日照: [119.2786, 35.5023], + 淄博: [118.0371, 36.6064], + 枣庄: [117.323, 34.8926], + 莱芜: [117.6526, 36.2714], + 恩施土家族苗族自治州: [109.5007, 30.2563], + 十堰: [110.5115, 32.3877], + 宜昌: [111.1707, 30.7617], + 襄樊: [111.9397, 31.9263], + 黄冈: [115.2686, 30.6628], + 荆州: [113.291, 30.0092], + 荆门: [112.6758, 30.9979], + 咸宁: [114.2578, 29.6631], + 随州: [113.4338, 31.8768], + 孝感: [113.9502, 31.1188], + 武汉: [114.3896, 30.6628], + 黄石: [115.0159, 29.9213], + 神农架林区: [110.4565, 31.5802], + 天门: [113.0273, 30.6409], + 仙桃: [113.3789, 30.3003], + 潜江: [112.7637, 30.3607], + 鄂州: [114.7302, 30.4102] + } + export default { + chinaGeoCoordMap + } +
\ No newline at end of file diff --git a/UI source code/dns_mapping_ui-master/src/utils/clipboard.js b/UI source code/dns_mapping_ui-master/src/utils/clipboard.js new file mode 100644 index 0000000..e916a44 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/clipboard.js @@ -0,0 +1,36 @@ +import Vue from 'vue' +import Clipboard from 'clipboard' + +function clipboardSuccess() { + Vue.prototype.$message({ + message: 'Copy successfully', + type: 'success', + duration: 1500 + }) +} + +function clipboardError() { + Vue.prototype.$message({ + message: 'Copy failed', + type: 'error' + }) +} + +export default function handleClipboard(text, event) { + const clipboard = new Clipboard(event.target, { + text: () => text + }) + clipboard.on('success', () => { + clipboardSuccess() + clipboard.off('error') + clipboard.off('success') + clipboard.destroy() + }) + clipboard.on('error', () => { + clipboardError() + clipboard.off('error') + clipboard.off('success') + clipboard.destroy() + }) + clipboard.onClick(event) +} diff --git a/UI source code/dns_mapping_ui-master/src/utils/datetime.js b/UI source code/dns_mapping_ui-master/src/utils/datetime.js new file mode 100644 index 0000000..67f808a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/datetime.js @@ -0,0 +1,216 @@ +/* eslint-disable */ + +/** + * Date对象的补充函数,包括类似Python中的strftime() + * 阿债 https://gitee.com/azhai/datetime.js + */ + +Date.prototype.toMidnight = function() { + this.setHours(0) + this.setMinutes(0) + this.setSeconds(0) + this.setMilliseconds(0) + return this +} + +Date.prototype.daysAgo = function(days, midnight) { + days = days ? days - 0 : 0 + const date = new Date(this.getTime() - days * 8.64E7) + return midnight ? date.toMidnight() : date +} + +Date.prototype.monthBegin = function(offset) { + offset = offset ? offset - 0 : 0 + const days = this.getDate() - 1 - offset + return this.daysAgo(days, true) +} + +Date.prototype.quarterBegin = function() { + const month = this.getMonth() - this.getMonth() % 3 + return new Date(this.getFullYear(), month, 1).toMidnight() +} + +Date.prototype.yearBegin = function() { + return new Date(this.getFullYear(), 0, 1).toMidnight() +} + +Date.prototype.strftime = function(format, local) { + if (!format) { + const str = new Date(this.getTime() + 2.88E7).toISOString() + return str.substr(0, 16).replace('T', ' ') + } + local = local && local.startsWith('zh') ? 'zh' : 'en' + const padZero = function(str, len) { + const pads = len - str.toString().length + return (pads && pads > 0 ? '0'.repeat(pads) : '') + str + } + format = format.replace('%F', '%Y-%m-%d') + format = format.replace(/%D|%x/, '%m/%d/%y') + format = format.replace(/%T|%X/, '%H:%M:%S') + format = format.replace('%R', '%H:%M') + format = format.replace('%r', '%H:%M:%S %p') + format = format.replace('%c', '%a %b %e %H:%M:%S %Y') + const _this = this + return format.replace(/%[A-Za-z%]/g, function(f) { + let ans = f + switch (f) { + case '%%': + ans = '%' + break + + case '%Y': + case '%G': + ans = _this.getFullYear() + break + + case '%y': + ans = _this.getFullYear() % 100 + break + + case '%C': + ans = _this.getFullYear() / 100 + break + + case '%m': + case '%n': + ans = _this.getMonth() + 1 + break + + case '%B': + local = local.startsWith('en') ? 'english' : local + + case '%b': + const m = _this.getMonth() + ans = local_labels.monthes[local][m] + break + + case '%d': + case '%e': + ans = _this.getDate() + break + + case '%j': + ans = _this.getDaysOfYear() + break + + case '%U': + case '%W': + const ws = _this.getWeeksOfYear(f === '%W') + ans = padZero(ws, 2) + break + + case '%w': + ans = _this.getDay() + + case '%u': + ans = ans === 0 ? 7 : ans + break + + case '%A': + local = local.startsWith('en') ? 'english' : local + + case '%a': + const d = _this.getDay() + ans = local_labels.weekdays[local][d] + break + + case '%H': + case '%k': + ans = _this.getHours() + break + + case '%I': + case '%l': + ans = _this.getHours() + ans = ans % 12 + break + + case '%M': + ans = _this.getMinutes() + break + + case '%S': + ans = _this.getSeconds() + break + + case '%s': + ans = parseInt(_this.getTime() / 1E3) + break + + case '%f': + const ms = _this.getMilliseconds() + ans = padZero(ms * 1E3, 6) + break + + case '%P': + local = local.startsWith('en') ? 'english' : local + + case '%p': + const h = _this.getHours() + ans = local_labels.meridians[local][h < 12 ? 0 : 1] + break + + case '%z': + let tzo = _this.getTimezoneOffset() + const sign = tzo < 0 ? '-' : '+' + tzo = Math.abs(tzo) + const ho = padZero(tzo / 60, 2) + const mo = padZero(tzo % 60, 2) + ans = sign + ho + mo + break + + default: + break + } + if (f === '%C' || f === '%y' || f === '%m' || f === '%d' || f === '%H' || f === '%M' || f === '%S') { + ans = padZero(ans, 2) + } + return ans.toString() + }) +} + +Date.prototype.humanize = function(local) { + local = local && local.startsWith('zh') ? 'zh' : 'en' + const result = this.strftime('', local) + const days = (Date.today() - this.toMidnight().getTime()) / 8.64E7 + if (days <= -10 || days >= 10) { + return result + } + const labels = local_labels.dayagos[local] + let lbl = '' + if (days === 0 || days === 1) { + lbl = labels[days] + } else if (days === -1) { + lbl = labels[2] + } else if (days >= 2) { + lbl = days + labels[3] + } else { + lbl = days + labels[4] + } + return lbl + result.substr(10, 6) +} + +const local_labels = { + monthes: { + english: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + en: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + zh: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'] + }, + weekdays: { + english: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + en: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + zh: ['日', '一', '二', '三', '四', '五', '六'] + }, + meridians: { + english: ['a.m.', 'p.m.'], + en: ['AM', 'PM'], + zh: ['上午', '下午'] + }, + dayagos: { + english: ['Today', 'Yesterday', 'Tomorrow', ' days ago', ' days late'], + en: ['Today', 'Yesterday', 'Tomorrow', ' days ago', ' days late'], + zh: ['今天', '昨天', '明天', '天前', '天后'] + } +} + +export default Date diff --git a/UI source code/dns_mapping_ui-master/src/utils/fackClickOutSide.js b/UI source code/dns_mapping_ui-master/src/utils/fackClickOutSide.js new file mode 100644 index 0000000..9b1f0a2 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/fackClickOutSide.js @@ -0,0 +1,45 @@ +let lock = true +let el = null +// const MousedownEvent = new Event('mousedown', { bubbles: true }) +// const MouseupEvent = new Event('mouseup', { bubbles: true }) +const MousedownEvent = document.createEvent('Events') +MousedownEvent.initEvent('mousedown', true, true) +const MouseupEvent = document.createEvent('Events') +MouseupEvent.initEvent('mouseup', true, true) +const fakeClickOutSide = () => { + document.dispatchEvent(MousedownEvent) + document.dispatchEvent(MouseupEvent) + lock = true // console.log('dispatchEvent'); +} +const mousedownHandle = e => { + const classList = e.target.classList + if (classList.contains('el-select__caret') || classList.contains('el-input__inner') || classList.contains('el-select__tags')) { + lock = false + return + } + if (lock) return + fakeClickOutSide() +} +const mousewheelHandle = e => { + if (lock || e.target.classList.contains('el-select-dropdown__item') || e.target.parentNode.classList.contains('el-select-dropdown__item') || e.target.classList.contains('el-cascader-node__label') || e.target.parentNode.classList.contains('el-cascader-node__label')) return + fakeClickOutSide() +} +const eventListener = (type) => { + el[type + 'EventListener']('mousedown', mousedownHandle) + window[type + 'EventListener']('mousewheel', mousewheelHandle) + window[type + 'EventListener']('DOMMouseScroll', mousewheelHandle) // fireFox 3.5+ +} +export default { + mounted() { + el = this.$root.$el + el.addFakeClickOutSideEventCount = el.addFakeClickOutSideEventCount || 0; + (!el.addFakeClickOutSideEventCount) && this.$nextTick(() => { + eventListener('add') + }) + el.addFakeClickOutSideEventCount += 1 + }, + destroyed() { + eventListener('remove') + el.addFakeClickOutSideEventCount -= 1 + } +} diff --git a/UI source code/dns_mapping_ui-master/src/utils/i18n.js b/UI source code/dns_mapping_ui-master/src/utils/i18n.js new file mode 100644 index 0000000..c1aca41 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/i18n.js @@ -0,0 +1,22 @@ +// translate router.meta.title, be used in breadcrumb sidebar tagsview +// export function generateTitle(title) { +// console.log(this.$te, 222) +// // const hasKey = this.$te('route.' + title) + +// if (hasKey) { +// // $t :this method from vue-i18n, inject in @/lang/index.js +// const translatedTitle = this.$t('route.' + title) + +// return translatedTitle +// } +// return title +// } + +// export function generateTitle(title){ +// const hasKey = this.$te('route.' + title) +// if(hasKey){ +// const translatedTitle = this.$t('route.' + title) +// return translatedTitle +// } +// return title +// } diff --git a/UI source code/dns_mapping_ui-master/src/utils/index.js b/UI source code/dns_mapping_ui-master/src/utils/index.js new file mode 100644 index 0000000..ab7ad30 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/index.js @@ -0,0 +1,388 @@ +/** + * Created by PanJiaChen on 16/11/18. + */ + +/** + * Parse the time to string + * @param {(Object|string|number)} time + * @param {string} cFormat + * @returns {string} + */ +export function parseTime(time, cFormat) { + if (arguments.length === 0) { + return null + } + const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}' + let date + if (typeof time === 'undefined' || time === null || time === 'null') { + return '' + } else if (typeof time === 'object') { + date = time + } else { + if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { + time = parseInt(time) + } + if ((typeof time === 'number') && (time.toString().length === 10)) { + time = time * 1000 + } + date = new Date(time) + } + const formatObj = { + y: date.getFullYear(), + m: date.getMonth() + 1, + d: date.getDate(), + h: date.getHours(), + i: date.getMinutes(), + s: date.getSeconds(), + a: date.getDay() + } + const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { + let value = formatObj[key] + // Note: getDay() returns 0 on Sunday + if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] } + if (result.length > 0 && value < 10) { + value = '0' + value + } + return value || 0 + }) + return time_str +} + +/** + * @param {number} time + * @param {string} option + * @returns {string} + */ +export function formatTime(time, option) { + if (('' + time).length === 10) { + time = parseInt(time) * 1000 + } else { + time = +time + } + const d = new Date(time) + const now = Date.now() + + const diff = (now - d) / 1000 + + if (diff < 30) { + return '刚刚' + } else if (diff < 3600) { + // less 1 hour + return Math.ceil(diff / 60) + '分钟前' + } else if (diff < 3600 * 24) { + return Math.ceil(diff / 3600) + '小时前' + } else if (diff < 3600 * 24 * 2) { + return '1天前' + } + if (option) { + return parseTime(time, option) + } else { + return ( + d.getMonth() + + 1 + + '月' + + d.getDate() + + '日' + + d.getHours() + + '时' + + d.getMinutes() + + '分' + ) + } +} + +/** + * @param {string} url + * @returns {Object} + */ +export function getQueryObject(url) { + url = url == null ? window.location.href : url + const search = url.substring(url.lastIndexOf('?') + 1) + const obj = {} + const reg = /([^?&=]+)=([^?&=]*)/g + search.replace(reg, (rs, $1, $2) => { + const name = decodeURIComponent($1) + let val = decodeURIComponent($2) + val = String(val) + obj[name] = val + return rs + }) + return obj +} + +/** + * @param {string} input value + * @returns {number} output value + */ +export function byteLength(str) { + // returns the byte length of an utf8 string + let s = str.length + for (var i = str.length - 1; i >= 0; i--) { + const code = str.charCodeAt(i) + if (code > 0x7f && code <= 0x7ff) s++ + else if (code > 0x7ff && code <= 0xffff) s += 2 + if (code >= 0xDC00 && code <= 0xDFFF) i-- + } + return s +} + +/** + * @param {Array} actual + * @returns {Array} + */ +export function cleanArray(actual) { + const newArray = [] + for (let i = 0; i < actual.length; i++) { + if (actual[i]) { + newArray.push(actual[i]) + } + } + return newArray +} + +/** + * @param {Object} json + * @returns {Array} + */ +export function param(json) { + if (!json) return '' + return cleanArray( + Object.keys(json).map(key => { + if (json[key] === undefined) return '' + return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]) + }) + ).join('&') +} + +/** + * @param {string} url + * @returns {Object} + */ +export function param2Obj(url) { + const search = url.split('?')[1] + if (!search) { + return {} + } + return JSON.parse( + '{"' + + decodeURIComponent(search) + .replace(/"/g, '\\"') + .replace(/&/g, '","') + .replace(/=/g, '":"') + .replace(/\+/g, ' ') + + '"}' + ) +} + +/** + * @param {string} val + * @returns {string} + */ +export function html2Text(val) { + const div = document.createElement('div') + div.innerHTML = val + return div.textContent || div.innerText +} + +/** + * Merges two objects, giving the last one precedence + * @param {Object} target + * @param {(Object|Array)} source + * @returns {Object} + */ +export function objectMerge(target, source) { + if (typeof target !== 'object') { + target = {} + } + if (Array.isArray(source)) { + return source.slice() + } + Object.keys(source).forEach(property => { + const sourceProperty = source[property] + if (typeof sourceProperty === 'object') { + target[property] = objectMerge(target[property], sourceProperty) + } else { + target[property] = sourceProperty + } + }) + return target +} + +/** + * @param {HTMLElement} element + * @param {string} className + */ +export function toggleClass(element, className) { + if (!element || !className) { + return + } + let classString = element.className + const nameIndex = classString.indexOf(className) + if (nameIndex === -1) { + classString += '' + className + } else { + classString = + classString.substr(0, nameIndex) + + classString.substr(nameIndex + className.length) + } + element.className = classString +} + +/** + * @param {string} type + * @returns {Date} + */ +export function getTime(type) { + if (type === 'start') { + return new Date().getTime() - 3600 * 1000 * 24 * 90 + } else { + return new Date(new Date().toDateString()) + } +} + +/** + * @param {Function} func + * @param {number} wait + * @param {boolean} immediate + * @return {*} + */ +export function debounce(func, wait, immediate) { + let timeout, args, context, timestamp, result + + const later = function() { + // 据上一次触发时间间隔 + const last = +new Date() - timestamp + + // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait + if (last < wait && last > 0) { + timeout = setTimeout(later, wait - last) + } else { + timeout = null + // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用 + if (!immediate) { + result = func.apply(context, args) + if (!timeout) context = args = null + } + } + } + + return function(...args) { + context = this + timestamp = +new Date() + const callNow = immediate && !timeout + // 如果延时不存在,重新设定延时 + if (!timeout) timeout = setTimeout(later, wait) + if (callNow) { + result = func.apply(context, args) + context = args = null + } + + return result + } +} + +/** + * This is just a simple version of deep copy + * Has a lot of edge cases bug + * If you want to use a perfect deep copy, use lodash's _.cloneDeep + * @param {Object} source + * @returns {Object} + */ +export function deepClone(source) { + if (!source && typeof source !== 'object') { + throw new Error('error arguments', 'deepClone') + } + const targetObj = source.constructor === Array ? [] : {} + Object.keys(source).forEach(keys => { + if (source[keys] && typeof source[keys] === 'object') { + targetObj[keys] = deepClone(source[keys]) + } else { + targetObj[keys] = source[keys] + } + }) + return targetObj +} + +/** + * @param {Array} arr + * @returns {Array} + */ +export function uniqueArr(arr) { + return Array.from(new Set(arr)) +} + +/** + * @returns {string} + */ +export function createUniqueString() { + const timestamp = +new Date() + '' + const randomNum = parseInt((1 + Math.random()) * 65536) + '' + return (+(randomNum + timestamp)).toString(32) +} + +/** + * Check if an element has a class + * @param {HTMLElement} elm + * @param {string} cls + * @returns {boolean} + */ +export function hasClass(ele, cls) { + return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) +} + +/** + * Add class to element + * @param {HTMLElement} elm + * @param {string} cls + */ +export function addClass(ele, cls) { + if (!hasClass(ele, cls)) ele.className += ' ' + cls +} + +/** + * Remove class from element + * @param {HTMLElement} elm + * @param {string} cls + */ +export function removeClass(ele, cls) { + if (hasClass(ele, cls)) { + const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)') + ele.className = ele.className.replace(reg, ' ') + } +} + +// 替换邮箱字符 +export function regEmail(email) { + if (String(email).indexOf('@') > 0) { + const str = email.split('@') + let _s = '' + if (str[0].length > 3) { + for (var i = 0; i < str[0].length - 3; i++) { + _s += '*' + } + } + var new_email = str[0].substr(0, 3) + _s + '@' + str[1] + } + return new_email +} + +// 替换手机字符 +export function regMobile(mobile) { + if (mobile.length > 7) { + var new_mobile = mobile.substr(0, 3) + '****' + mobile.substr(7) + } + return new_mobile +} + +// 下载文件 +export function downloadFile(obj, name, suffix) { + const url = window.URL.createObjectURL(new Blob([obj])) + const link = document.createElement('a') + link.style.display = 'none' + link.href = url + const fileName = parseTime(new Date()) + '-' + name + '.' + suffix + link.setAttribute('download', fileName) + document.body.appendChild(link) + link.click() + document.body.removeChild(link) +} diff --git a/UI source code/dns_mapping_ui-master/src/utils/permission.js b/UI source code/dns_mapping_ui-master/src/utils/permission.js new file mode 100644 index 0000000..b0c7523 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/permission.js @@ -0,0 +1,23 @@ +import store from '@/store' + +/** + * @param {Array} value + * @returns {Boolean} + * @example see @/views/permission/directive.vue + */ +export default { + install(Vue) { + Vue.prototype.checkPer = (value) => { + if (value && value instanceof Array && value.length > 0) { + const roles = store.getters && store.getters.roles + const permissionRoles = value + return roles.some(role => { + return permissionRoles.includes(role) + }) + } else { + console.error(`need roles! Like v-permission="['admin','editor']"`) + return false + } + } + } +} diff --git a/UI source code/dns_mapping_ui-master/src/utils/request.js b/UI source code/dns_mapping_ui-master/src/utils/request.js new file mode 100644 index 0000000..ce7fd1b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/request.js @@ -0,0 +1,88 @@ +import axios from 'axios' +import router from '@/router/routers' +import { Notification } from 'element-ui' +import store from '../store' +import { getToken } from '@/utils/auth' +import Config from '@/settings' +import Cookies from 'js-cookie' + +// 创建axios实例 +const service = axios.create({ + baseURL: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_API : '/', // api 的 base_url + timeout: Config.timeout // 请求超时时间 +}) + +// request拦截器 +service.interceptors.request.use( + config => { + if (getToken()) { + config.headers['Authorization'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 + } + config.headers['Content-Type'] = 'application/json' + return config + }, + error => { + Promise.reject(error) + } +) + +// response 拦截器 +service.interceptors.response.use( + response => { + return response.data + }, + error => { + // 兼容blob下载出错json提示 + if (error.response.data instanceof Blob && error.response.data.type.toLowerCase().indexOf('json') !== -1) { + const reader = new FileReader() + reader.readAsText(error.response.data, 'utf-8') + reader.onload = function(e) { + const errorMsg = JSON.parse(reader.result).message + Notification.error({ + title: errorMsg, + duration: 5000 + }) + } + } else { + let code = 0 + try { + code = error.response.data.status + } catch (e) { + if (error.toString().indexOf('Error: timeout') !== -1) { + Notification.error({ + title: '网络请求超时', + duration: 5000 + }) + return Promise.reject(error) + } + } + console.log(code) + if (code) { + if (code === 401) { + store.dispatch('LogOut').then(() => { + // 用户登录界面提示 + Cookies.set('point', 401) + location.reload() + }) + } else if (code === 403) { + router.push({ path: '/401' }) + } else { + const errorMsg = error.response.data.message + if (errorMsg !== undefined) { + Notification.error({ + title: errorMsg, + duration: 5000 + }) + } + } + } else { + Notification.error({ + title: '接口请求失败', + duration: 5000 + }) + } + } + return Promise.reject(error) + } +) +export default service diff --git a/UI source code/dns_mapping_ui-master/src/utils/rsaEncrypt.js b/UI source code/dns_mapping_ui-master/src/utils/rsaEncrypt.js new file mode 100644 index 0000000..1948ddd --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/rsaEncrypt.js @@ -0,0 +1,14 @@ +import JSEncrypt from 'jsencrypt/bin/jsencrypt.min' + +// 密钥对生成 http://web.chacuo.net/netrsakeypair + +const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD\n' + + '2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ==' + +// 加密 +export function encrypt(txt) { + const encryptor = new JSEncrypt() + encryptor.setPublicKey(publicKey) // 设置公钥 + return encryptor.encrypt(txt) // 对需要加密的数据进行加密 +} + diff --git a/UI source code/dns_mapping_ui-master/src/utils/shortcuts.js b/UI source code/dns_mapping_ui-master/src/utils/shortcuts.js new file mode 100644 index 0000000..d92edc3 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/shortcuts.js @@ -0,0 +1,108 @@ +import Date from './datetime.js' + +export const calendarBaseShortcuts = [{ + text: '今天', + onClick(picker) { + const startTime = new Date(new Date().setHours(0, 0, 0)) + const endTime = new Date(new Date().setHours(23, 59, 59)) + picker.$emit('pick', [startTime, endTime]) + } +}, { + text: '昨天', + onClick(picker) { + const startTime = new Date(new Date().daysAgo(1).setHours(0, 0, 0)) + const endTime = new Date(new Date().daysAgo(1).setHours(23, 59, 59)) + picker.$emit('pick', [startTime, endTime]) + } +}, { + text: '最近一周', + onClick(picker) { + const startTime = new Date(new Date().daysAgo(7).setHours(0, 0, 0)) + const endTime = new Date(new Date().setHours(23, 59, 59)) + picker.$emit('pick', [startTime, endTime]) + } +}, { + text: '最近30天', + onClick(picker) { + const startTime = new Date(new Date().daysAgo(30).setHours(0, 0, 0)) + const endTime = new Date(new Date().setHours(23, 59, 59)) + picker.$emit('pick', [startTime, endTime]) + } +}, { + text: '这个月', + onClick(picker) { + const startTime = new Date(new Date().monthBegin().setHours(0, 0, 0)) + const endTime = new Date(new Date().setHours(23, 59, 59)) + picker.$emit('pick', [startTime, endTime]) + } +}, { + text: '本季度', + onClick(picker) { + const startTime = new Date(new Date().quarterBegin().setHours(0, 0, 0)) + const endTime = new Date(new Date().setHours(23, 59, 59)) + picker.$emit('pick', [startTime, endTime]) + } +}] + +export const calendarMoveShortcuts = [{ + text: '‹ 往前一天 ', + onClick(picker) { + let startTime = new Date(new Date().daysAgo(1).setHours(0, 0, 0)) + let endTime = new Date(new Date().daysAgo(1).setHours(23, 59, 59)) + if (!picker.value) { + picker.value = [startTime, endTime] + } + startTime = picker.value[0].daysAgo(1) + endTime = picker.value[1].daysAgo(1) + picker.$emit('pick', [startTime, endTime]) + } +}, { + text: ' 往后一天 ›', + onClick(picker) { + let startTime = new Date(new Date().setHours(0, 0, 0)) + let endTime = new Date(new Date().setHours(23, 59, 59)) + if (!picker.value) { + picker.value = [startTime, endTime] + } + startTime = picker.value[0].daysAgo(-1) + endTime = picker.value[1].daysAgo(-1) + picker.$emit('pick', [startTime, endTime]) + } +}, { + text: '« 往前一周 ', + onClick(picker) { + let startTime = new Date(new Date().setHours(0, 0, 0)) + let endTime = new Date(new Date().setHours(23, 59, 59)) + if (!picker.value) { + picker.value = [startTime.daysAgo(new Date().getDay()), + endTime.daysAgo(new Date().getDay() + 1)] + } else { + picker.value = [picker.value[0].daysAgo(picker.value[0].getDay()), + picker.value[1].daysAgo(picker.value[1].getDay() + 1)] + } + startTime = picker.value[0].daysAgo(7) + endTime = picker.value[1] + picker.$emit('pick', [startTime, endTime]) + } +}, { + text: ' 往后一周 »', + onClick(picker) { + let startTime = new Date(new Date().setHours(0, 0, 0)) + let endTime = new Date(new Date().setHours(23, 59, 59)) + if (!picker.value) { + picker.value = [startTime.daysAgo(new Date().getDay() - 7), + endTime.daysAgo(new Date().getDay() - 6)] + } else { + picker.value = [picker.value[0].daysAgo(picker.value[0].getDay() - 7), + picker.value[1].daysAgo(picker.value[1].getDay() - 6)] + } + startTime = picker.value[0] + endTime = picker.value[1].daysAgo(-7) + picker.$emit('pick', [startTime, endTime]) + } +}] + +export const calendarShortcuts = [ + ...calendarBaseShortcuts, + ...calendarMoveShortcuts +] diff --git a/UI source code/dns_mapping_ui-master/src/utils/upload.js b/UI source code/dns_mapping_ui-master/src/utils/upload.js new file mode 100644 index 0000000..945414b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/upload.js @@ -0,0 +1,11 @@ +import axios from 'axios' +import { getToken } from '@/utils/auth' + +export function upload(api, file) { + var data = new FormData() + data.append('file', file) + const config = { + headers: { 'Authorization': getToken() } + } + return axios.post(api, data, config) +} diff --git a/UI source code/dns_mapping_ui-master/src/utils/validate.js b/UI source code/dns_mapping_ui-master/src/utils/validate.js new file mode 100644 index 0000000..751f94f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/utils/validate.js @@ -0,0 +1,167 @@ +/** + * Created by PanJiaChen on 16/11/18. + */ + +/** + * @param {string} path + * @returns {Boolean} + */ +export function isExternal(path) { + return /^(https?:|mailto:|tel:)/.test(path) +} + +/** + * @param {string} str + * @returns {Boolean} + */ +export function validUsername(str) { + const valid_map = ['admin', 'editor'] + return valid_map.indexOf(str.trim()) >= 0 +} + +/** + * @param {string} url + * @returns {Boolean} + */ +export function validURL(url) { + const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ + return reg.test(url) +} + +/** + * @param {string} str + * @returns {Boolean} + */ +export function validLowerCase(str) { + const reg = /^[a-z]+$/ + return reg.test(str) +} + +/** + * @param {string} str + * @returns {Boolean} + */ +export function validUpperCase(str) { + const reg = /^[A-Z]+$/ + return reg.test(str) +} + +/** + * @param {string} str + * @returns {Boolean} + */ +export function validAlphabets(str) { + const reg = /^[A-Za-z]+$/ + return reg.test(str) +} + +/** + * @param {string} email + * @returns {Boolean} + */ +export function validEmail(email) { + const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + return reg.test(email) +} + +export function isvalidPhone(phone) { + const reg = /^1([38][0-9]|4[014-9]|[59][0-35-9]|6[2567]|7[0-8])\d{8}$/ + return reg.test(phone) +} + +/** + * @param {string} str + * @returns {Boolean} + */ +export function isString(str) { + if (typeof str === 'string' || str instanceof String) { + return true + } + return false +} + +/** + * @param {Array} arg + * @returns {Boolean} + */ +export function isArray(arg) { + if (typeof Array.isArray === 'undefined') { + return Object.prototype.toString.call(arg) === '[object Array]' + } + return Array.isArray(arg) +} + +/** + * 是否合法IP地址 + * @param rule + * @param value + * @param callback + */ +export function validateIP(rule, value, callback) { + if (value === '' || value === undefined || value == null) { + callback() + } else { + const reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/ + if ((!reg.test(value)) && value !== '') { + callback(new Error('请输入正确的IP地址')) + } else { + callback() + } + } +} + +/* 是否手机号码或者固话*/ +export function validatePhoneTwo(rule, value, callback) { + const reg = /^((0\d{2,3}-\d{7,8})|(1([38][0-9]|4[014-9]|[59][0-35-9]|6[2567]|7[0-8])\d{8}))$/ + if (value === '' || value === undefined || value == null) { + callback() + } else { + if ((!reg.test(value)) && value !== '') { + callback(new Error('请输入正确的电话号码或者固话号码')) + } else { + callback() + } + } +} + +/* 是否固话*/ +export function validateTelephone(rule, value, callback) { + const reg = /0\d{2}-\d{7,8}/ + if (value === '' || value === undefined || value == null) { + callback() + } else { + if ((!reg.test(value)) && value !== '') { + callback(new Error('请输入正确的固话(格式:区号+号码,如010-1234567)')) + } else { + callback() + } + } +} + +/* 是否手机号码*/ +export function validatePhone(rule, value, callback) { + const reg = /^1([38][0-9]|4[014-9]|[59][0-35-9]|6[2567]|7[0-8])\d{8}$/ + if (value === '' || value === undefined || value == null) { + callback() + } else { + if ((!reg.test(value)) && value !== '') { + callback(new Error('请输入正确的电话号码')) + } else { + callback() + } + } +} + +/* 是否身份证号码*/ +export function validateIdNo(rule, value, callback) { + const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/ + if (value === '' || value === undefined || value == null) { + callback() + } else { + if ((!reg.test(value)) && value !== '') { + callback(new Error('请输入正确的身份证号码')) + } else { + callback() + } + } +} diff --git a/UI source code/dns_mapping_ui-master/src/views/components/Echarts.vue b/UI source code/dns_mapping_ui-master/src/views/components/Echarts.vue new file mode 100644 index 0000000..86533c3 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/components/Echarts.vue @@ -0,0 +1,19 @@ +<template> + <div class="dashboard-container"> + + </div> +</template> + +<script> + + + + +export default { + +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/components/Editor.vue b/UI source code/dns_mapping_ui-master/src/views/components/Editor.vue new file mode 100644 index 0000000..ced461c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/components/Editor.vue @@ -0,0 +1,74 @@ +<template> + <div class="app-container"> + <p class="warn-content"> + 富文本基于 + <el-link type="primary" href="https://www.kancloud.cn/wangfupeng/wangeditor3/332599" target="_blank">wangEditor</el-link> + </p> + <el-row :gutter="10"> + <el-col :xs="24" :sm="24" :md="15" :lg="15" :xl="15"> + <div ref="editor" class="text" /> + </el-col> + <el-col :xs="24" :sm="24" :md="9" :lg="9" :xl="9"> + <div v-html="editorContent" /> + </el-col> + </el-row> + </div> +</template> + +<script> +import { mapGetters } from 'vuex' +import { upload } from '@/utils/upload' +import E from 'wangeditor' +export default { + name: 'Editor', + data() { + return { + editorContent: + ` + <ul> + <li>更多帮助请查看官方文档:<a style="color: #42b983" target="_blank" href="https://www.wangeditor.com/doc/">wangEditor</a></li> + </ul> + ` + } + }, + computed: { + ...mapGetters([ + 'imagesUploadApi', + 'baseApi' + ]) + }, + mounted() { + const _this = this + var editor = new E(this.$refs.editor) + // 自定义菜单配置 + editor.config.zIndex = 5 + // 文件上传 + editor.config.customUploadImg = function(files, insert) { + // files 是 input 中选中的文件列表 + // insert 是获取图片 url 后,插入到编辑器的方法 + files.forEach(image => { + upload(_this.imagesUploadApi, image).then(res => { + const data = res.data + const url = _this.baseApi + '/file/' + data.type + '/' + data.realName + insert(url) + }) + }) + } + editor.config.onchange = (html) => { + this.editorContent = html + } + editor.create() + // 初始化数据 + editor.txt.html(this.editorContent) + } +} +</script> + +<style scoped> + .text { + text-align:left; + } + ::v-deep .w-e-text-container { + height: 420px !important; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/components/MarkDown.vue b/UI source code/dns_mapping_ui-master/src/views/components/MarkDown.vue new file mode 100644 index 0000000..bb5a10e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/components/MarkDown.vue @@ -0,0 +1,49 @@ +<template> + <div class="app-container"> + <p class="warn-content"> + Markdown 基于 + <el-link type="primary" href="https://github.com/hinesboy/mavonEditor" target="_blank">MavonEditor</el-link> + </p> + <mavon-editor ref="md" :style="'height:' + height" @imgAdd="imgAdd" /> + </div> +</template> + +<script> +import { upload } from '@/utils/upload' +import { mapGetters } from 'vuex' +export default { + name: 'Markdown', + data() { + return { + height: document.documentElement.clientHeight - 200 + 'px' + } + }, + computed: { + ...mapGetters([ + 'imagesUploadApi', + 'baseApi' + ]) + }, + mounted() { + const that = this + window.onresize = function temp() { + that.height = document.documentElement.clientHeight - 200 + 'px' + } + }, + methods: { + imgAdd(pos, $file) { + upload(this.imagesUploadApi, $file).then(res => { + const data = res.data + const url = this.baseApi + '/file/' + data.type + '/' + data.realName + this.$refs.md.$img2Url(pos, url) + }) + } + } +} +</script> + +<style scoped> + .v-note-wrapper.shadow { + z-index: 5; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/components/YamlEdit.vue b/UI source code/dns_mapping_ui-master/src/views/components/YamlEdit.vue new file mode 100644 index 0000000..9455fde --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/components/YamlEdit.vue @@ -0,0 +1,207 @@ +<template> + <div class="app-container"> + <p class="warn-content"> + Yaml编辑器 基于 + <a href="https://github.com/codemirror/CodeMirror" target="_blank">CodeMirror</a>, + 主题预览地址 <a href="https://codemirror.net/demo/theme.html#idea" target="_blank">Theme</a> + </p> + <Yaml :value="value" :height="height" /> + </div> +</template> + +<script> +import Yaml from '@/components/YamlEdit/index' +export default { + name: 'YamlEdit', + components: { Yaml }, + data() { + return { + height: document.documentElement.clientHeight - 210 + 'px', + value: '# 展示数据,如需更换主题,请在src/components/YamlEdit 目录中搜索原主题名称进行替换\n' + + '\n' + + '# ===================================================================\n' + + '# Spring Boot configuration.\n' + + '#\n' + + '# This configuration will be overridden by the Spring profile you use,\n' + + '# for example application-dev.yml if you use the "dev" profile.\n' + + '#\n' + + '# More information on profiles: https://www.jhipster.tech/profiles/\n' + + '# More information on configuration properties: https://www.jhipster.tech/common-application-properties/\n' + + '# ===================================================================\n' + + '\n' + + '# ===================================================================\n' + + '# Standard Spring Boot properties.\n' + + '# Full reference is available at:\n' + + '# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html\n' + + '# ===================================================================\n' + + '\n' + + 'eureka:\n' + + ' client:\n' + + ' enabled: true\n' + + ' healthcheck:\n' + + ' enabled: true\n' + + ' fetch-registry: true\n' + + ' register-with-eureka: true\n' + + ' instance-info-replication-interval-seconds: 10\n' + + ' registry-fetch-interval-seconds: 10\n' + + ' instance:\n' + + ' appname: product\n' + + ' instanceId: product:${spring.application.instance-id:${random.value}}\n' + + ' #instanceId: 127.0.0.1:9080\n' + + ' lease-renewal-interval-in-seconds: 5\n' + + ' lease-expiration-duration-in-seconds: 10\n' + + ' status-page-url-path: ${management.endpoints.web.base-path}/info\n' + + ' health-check-url-path: ${management.endpoints.web.base-path}/health\n' + + ' metadata-map:\n' + + ' zone: primary # This is needed for the load balancer\n' + + ' profile: ${spring.profiles.active}\n' + + ' version: ${info.project.version:}\n' + + ' git-version: ${git.commit.id.describe:}\n' + + ' git-commit: ${git.commit.id.abbrev:}\n' + + ' git-branch: ${git.branch:}\n' + + 'ribbon:\n' + + ' ReadTimeout: 120000\n' + + ' ConnectTimeout: 300000\n' + + ' eureka:\n' + + ' enabled: true\n' + + 'zuul:\n' + + ' host:\n' + + ' connect-timeout-millis: 5000\n' + + ' max-per-route-connections: 10000\n' + + ' max-total-connections: 5000\n' + + ' socket-timeout-millis: 60000\n' + + ' semaphore:\n' + + ' max-semaphores: 500\n' + + '\n' + + 'feign:\n' + + ' hystrix:\n' + + ' enabled: true\n' + + ' client:\n' + + ' config:\n' + + ' default:\n' + + ' connectTimeout: 500000\n' + + ' readTimeout: 500000\n' + + '\n' + + '# See https://github.com/Netflix/Hystrix/wiki/Configuration\n' + + 'hystrix:\n' + + ' command:\n' + + ' default:\n' + + ' circuitBreaker:\n' + + ' sleepWindowInMilliseconds: 100000\n' + + ' forceClosed: true\n' + + ' execution:\n' + + ' isolation:\n' + + '# strategy: SEMAPHORE\n' + + '# See https://github.com/spring-cloud/spring-cloud-netflix/issues/1330\n' + + ' thread:\n' + + ' timeoutInMilliseconds: 60000\n' + + ' shareSecurityContext: true\n' + + '\n' + + 'management:\n' + + ' endpoints:\n' + + ' web:\n' + + ' base-path: /management\n' + + ' exposure:\n' + + ' include: ["configprops", "env", "health", "info", "threaddump"]\n' + + ' endpoint:\n' + + ' health:\n' + + ' show-details: when_authorized\n' + + ' info:\n' + + ' git:\n' + + ' mode: full\n' + + ' health:\n' + + ' mail:\n' + + ' enabled: false # When using the MailService, configure an SMTP server and set this to true\n' + + ' metrics:\n' + + ' enabled: false # http://micrometer.io/ is disabled by default, as we use http://metrics.dropwizard.io/ instead\n' + + '\n' + + 'spring:\n' + + ' application:\n' + + ' name: product\n' + + ' jpa:\n' + + ' open-in-view: false\n' + + ' hibernate:\n' + + ' ddl-auto: update\n' + + ' naming:\n' + + ' physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy\n' + + ' implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy\n' + + ' messages:\n' + + ' basename: i18n/messages\n' + + ' mvc:\n' + + ' favicon:\n' + + ' enabled: false\n' + + ' thymeleaf:\n' + + ' mode: HTML\n' + + 'security:\n' + + ' oauth2:\n' + + ' resource:\n' + + ' filter-order: 3\n' + + '\n' + + 'server:\n' + + ' servlet:\n' + + ' session:\n' + + ' cookie:\n' + + ' http-only: true\n' + + '\n' + + '# Properties to be exposed on the /info management endpoint\n' + + 'info:\n' + + ' # Comma separated list of profiles that will trigger the ribbon to show\n' + + ' display-ribbon-on-profiles: "dev"\n' + + '\n' + + '# ===================================================================\n' + + '# JHipster specific properties\n' + + '#\n' + + '# Full reference is available at: https://www.jhipster.tech/common-application-properties/\n' + + '# ===================================================================\n' + + '\n' + + 'jhipster:\n' + + ' async:\n' + + ' core-pool-size: 2\n' + + ' max-pool-size: 50\n' + + ' queue-capacity: 10000\n' + + ' # By default CORS is disabled. Uncomment to enable.\n' + + ' #cors:\n' + + ' #allowed-origins: "*"\n' + + ' #allowed-methods: "*"\n' + + ' #allowed-headers: "*"\n' + + ' #exposed-headers: "Authorization,Link,X-Total-Count"\n' + + ' #allow-credentials: true\n' + + ' #max-age: 1800\n' + + ' mail:\n' + + ' from: product@localhost\n' + + ' swagger:\n' + + ' default-include-pattern: /api/.*\n' + + ' title: product API\n' + + ' description: product API documentation\n' + + ' version: 0.0.1\n' + + ' terms-of-service-url:\n' + + ' contact-name:\n' + + ' contact-url:\n' + + ' contact-email:\n' + + ' license:\n' + + ' license-url:\n' + + '\n' + + '# ===================================================================\n' + + '# Application specific properties\n' + + '# Add your own application properties here, see the ApplicationProperties class\n' + + '# to have type-safe configuration, like in the JHipsterProperties above\n' + + '#\n' + + '# More documentation is available at:\n' + + '# https://www.jhipster.tech/common-application-properties/\n' + + '# ===================================================================\n' + + '\n' + + '# application:\n' + } + }, + mounted() { + const that = this + window.onresize = function temp() { + that.height = document.documentElement.clientHeight - 210 + 'px' + } + } +} +</script> + +<style scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/components/excel/upload-excel.vue b/UI source code/dns_mapping_ui-master/src/views/components/excel/upload-excel.vue new file mode 100644 index 0000000..75f7634 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/components/excel/upload-excel.vue @@ -0,0 +1,41 @@ +<template> + <div class="app-container"> + <upload-excel-component :on-success="handleSuccess" :before-upload="beforeUpload" /> + <el-table :data="tableData" border highlight-current-row style="width: 100%;margin-top:20px;"> + <el-table-column v-for="item of tableHeader" :key="item" :prop="item" :label="item" /> + </el-table> + </div> +</template> + +<script> +import UploadExcelComponent from '@/components/UploadExcel/index.vue' + +export default { + name: 'UploadExcel', + components: { UploadExcelComponent }, + data() { + return { + tableData: [], + tableHeader: [] + } + }, + methods: { + beforeUpload(file) { + const isLt1M = file.size / 1024 / 1024 < 1 + if (isLt1M) { + return true + } + + this.$message({ + message: '请不要上传大于1m的文件.', + type: 'warning' + }) + return false + }, + handleSuccess({ results, header }) { + this.tableData = results + this.tableHeader = header + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/views/components/icons/element-icons.js b/UI source code/dns_mapping_ui-master/src/views/components/icons/element-icons.js new file mode 100644 index 0000000..df72201 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/components/icons/element-icons.js @@ -0,0 +1,74 @@ +const elementIcons = [ + 'info', + 'error', + 'success', + 'warning', + 'question', + 'back', + 'arrow-left', + 'arrow-down', + 'arrow-right', + 'arrow-up', + 'caret-left', + 'caret-bottom', + 'caret-top', + 'caret-right', + 'd-arrow-left', + 'd-arrow-right', + 'minus', + 'plus', + 'remove', + 'circle-plus', + 'remove-outline', + 'circle-plus-outline', + 'close', + 'check', + 'circle-close', + 'circle-check', + 'circle-close-outline', + 'circle-check-outline', + 'zoom-out', + 'zoom-in', + 'd-caret', + 'sort', + 'sort-down', + 'sort-up', + 'tickets', + 'document', + 'goods', + 'sold-out', + 'news', + 'message', + 'date', + 'printer', + 'time', + 'bell', + 'mobile-phone', + 'service', + 'view', + 'menu', + 'more', + 'more-outline', + 'star-on', + 'star-off', + 'location', + 'location-outline', + 'phone', + 'phone-outline', + 'picture', + 'picture-outline', + 'delete', + 'search', + 'edit', + 'edit-outline', + 'rank', + 'refresh', + 'share', + 'setting', + 'upload', + 'upload2', + 'download', + 'loading' +] + +export default elementIcons diff --git a/UI source code/dns_mapping_ui-master/src/views/components/icons/index.vue b/UI source code/dns_mapping_ui-master/src/views/components/icons/index.vue new file mode 100644 index 0000000..d060173 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/components/icons/index.vue @@ -0,0 +1,97 @@ +<template> + <div class="icons-container"> + <aside> + <a href="https://panjiachen.github.io/vue-element-admin-site/guide/advanced/icon.html" target="_blank">Add and use + </a> + </aside> + <el-tabs type="border-card"> + <el-tab-pane label="Icons"> + <div class="grid"> + <div v-for="item of svgIcons" :key="item" @click="handleClipboard(generateIconCode(item),$event)"> + <el-tooltip placement="top"> + <div slot="content"> + {{ generateIconCode(item) }} + </div> + <div class="icon-item"> + <svg-icon :icon-class="item" class-name="disabled" /> + <span>{{ item }}</span> + </div> + </el-tooltip> + </div> + </div> + </el-tab-pane> + <el-tab-pane label="Element-UI Icons"> + <div class="grid"> + <div v-for="item of elementIcons" :key="item" @click="handleClipboard(generateElementIconCode(item),$event)"> + <el-tooltip placement="top"> + <div slot="content"> + {{ generateElementIconCode(item) }} + </div> + <div class="icon-item"> + <i :class="'el-icon-' + item" /> + <span>{{ item }}</span> + </div> + </el-tooltip> + </div> + </div> + </el-tab-pane> + </el-tabs> + </div> +</template> + +<script> +import clipboard from '@/utils/clipboard' +import svgIcons from './svg-icons' +import elementIcons from './element-icons' +export default { + name: 'Icons', + data() { + return { + svgIcons, + elementIcons + } + }, + methods: { + generateIconCode(symbol) { + return `<svg-icon icon-class="${symbol}" />` + }, + generateElementIconCode(symbol) { + return `<i class="el-icon-${symbol}" />` + }, + handleClipboard(text, event) { + clipboard(text, event) + } + } +} +</script> + +<style lang="scss" scoped> +.icons-container { + margin: 10px 20px 0; + overflow: hidden; + + .grid { + position: relative; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); + } + .icon-item { + margin: 20px; + height: 85px; + text-align: center; + width: 100px; + float: left; + font-size: 30px; + color: #24292e; + cursor: pointer; + } + span { + display: block; + font-size: 16px; + margin-top: 10px; + } + .disabled { + pointer-events: none; + } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/components/icons/svg-icons.js b/UI source code/dns_mapping_ui-master/src/views/components/icons/svg-icons.js new file mode 100644 index 0000000..724cd8e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/components/icons/svg-icons.js @@ -0,0 +1,10 @@ +const req = require.context('../../../assets/icons/svg', false, /\.svg$/) +const requireAll = requireContext => requireContext.keys() + +const re = /\.\/(.*)\.svg/ + +const svgIcons = requireAll(req).map(i => { + return i.match(re)[1] +}) + +export default svgIcons diff --git a/UI source code/dns_mapping_ui-master/src/views/dashboard/LineChart.vue b/UI source code/dns_mapping_ui-master/src/views/dashboard/LineChart.vue new file mode 100644 index 0000000..e654168 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/dashboard/LineChart.vue @@ -0,0 +1,135 @@ +<template> + <div :class="className" :style="{height:height,width:width}" /> +</template> + +<script> +import echarts from 'echarts' +require('echarts/theme/macarons') // echarts theme +import resize from './mixins/resize' + +export default { + mixins: [resize], + props: { + className: { + type: String, + default: 'chart' + }, + width: { + type: String, + default: '100%' + }, + height: { + type: String, + default: '350px' + }, + autoResize: { + type: Boolean, + default: true + }, + chartData: { + type: Object, + required: true + } + }, + data() { + return { + chart: null + } + }, + watch: { + chartData: { + deep: true, + handler(val) { + this.setOptions(val) + } + } + }, + mounted() { + this.$nextTick(() => { + this.initChart() + }) + }, + beforeDestroy() { + if (!this.chart) { + return + } + this.chart.dispose() + this.chart = null + }, + methods: { + initChart() { + this.chart = echarts.init(this.$el, 'macarons') + this.setOptions(this.chartData) + }, + setOptions({ expectedData, actualData } = {}) { + this.chart.setOption({ + xAxis: { + data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + boundaryGap: false, + axisTick: { + show: false + } + }, + grid: { + left: 10, + right: 10, + bottom: 20, + top: 30, + containLabel: true + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'cross' + }, + padding: [5, 10] + }, + yAxis: { + axisTick: { + show: false + } + }, + legend: { + data: ['expected', 'actual'] + }, + series: [{ + name: 'expected', itemStyle: { + normal: { + color: '#FF005A', + lineStyle: { + color: '#FF005A', + width: 2 + } + } + }, + smooth: true, + type: 'line', + data: expectedData, + animationDuration: 2800, + animationEasing: 'cubicInOut' + }, + { + name: 'actual', + smooth: true, + type: 'line', + itemStyle: { + normal: { + color: '#3888fa', + lineStyle: { + color: '#3888fa', + width: 2 + }, + areaStyle: { + color: '#f3f8ff' + } + } + }, + data: actualData, + animationDuration: 2800, + animationEasing: 'quadraticOut' + }] + }) + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/views/dashboard/PanelGroup.vue b/UI source code/dns_mapping_ui-master/src/views/dashboard/PanelGroup.vue new file mode 100644 index 0000000..fe1815f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/dashboard/PanelGroup.vue @@ -0,0 +1,181 @@ +<template> + <el-row :gutter="40" class="panel-group"> + <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> + <div class="card-panel" @click="handleSetLineChartData('newVisitis')"> + <div class="card-panel-icon-wrapper icon-people"> + <svg-icon icon-class="peoples" class-name="card-panel-icon" /> + </div> + <div class="card-panel-description"> + <div class="card-panel-text"> + New Visits + </div> + <count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" /> + </div> + </div> + </el-col> + <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> + <div class="card-panel" @click="handleSetLineChartData('messages')"> + <div class="card-panel-icon-wrapper icon-message"> + <svg-icon icon-class="message" class-name="card-panel-icon" /> + </div> + <div class="card-panel-description"> + <div class="card-panel-text"> + Messages + </div> + <count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" /> + </div> + </div> + </el-col> + <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> + <div class="card-panel" @click="handleSetLineChartData('purchases')"> + <div class="card-panel-icon-wrapper icon-money"> + <svg-icon icon-class="money" class-name="card-panel-icon" /> + </div> + <div class="card-panel-description"> + <div class="card-panel-text"> + Purchases + </div> + <count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" /> + </div> + </div> + </el-col> + <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> + <div class="card-panel" @click="handleSetLineChartData('shoppings')"> + <div class="card-panel-icon-wrapper icon-shopping"> + <svg-icon icon-class="shopping" class-name="card-panel-icon" /> + </div> + <div class="card-panel-description"> + <div class="card-panel-text"> + Shoppings + </div> + <count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" /> + </div> + </div> + </el-col> + </el-row> +</template> + +<script> +import CountTo from 'vue-count-to' + +export default { + components: { + CountTo + }, + methods: { + handleSetLineChartData(type) { + this.$emit('handleSetLineChartData', type) + } + } +} +</script> + +<style lang="scss" scoped> +.panel-group { + margin-top: 18px; + + .card-panel-col { + margin-bottom: 32px; + } + + .card-panel { + height: 108px; + cursor: pointer; + font-size: 12px; + position: relative; + overflow: hidden; + color: #666; + background: #fff; + box-shadow: 4px 4px 40px rgba(0, 0, 0, .05); + border-color: rgba(0, 0, 0, .05); + + &:hover { + .card-panel-icon-wrapper { + color: #fff; + } + + .icon-people { + background: #40c9c6; + } + + .icon-message { + background: #36a3f7; + } + + .icon-money { + background: #f4516c; + } + + .icon-shopping { + background: #34bfa3 + } + } + + .icon-people { + color: #40c9c6; + } + + .icon-message { + color: #36a3f7; + } + + .icon-money { + color: #f4516c; + } + + .icon-shopping { + color: #34bfa3 + } + + .card-panel-icon-wrapper { + float: left; + margin: 14px 0 0 14px; + padding: 16px; + transition: all 0.38s ease-out; + border-radius: 6px; + } + + .card-panel-icon { + float: left; + font-size: 48px; + } + + .card-panel-description { + float: right; + font-weight: bold; + margin: 26px; + margin-left: 0px; + + .card-panel-text { + line-height: 18px; + color: rgba(0, 0, 0, 0.45); + font-size: 16px; + margin-bottom: 12px; + } + + .card-panel-num { + font-size: 20px; + } + } + } +} + +// @media (max-width:550px) { +// .card-panel-description { +// display: none; +// } + +// .card-panel-icon-wrapper { +// float: none !important; +// width: 100%; +// height: 100%; +// margin: 0 !important; + +// .svg-icon { +// display: block; +// margin: 14px auto !important; +// float: none !important; +// } +// } +// } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/dashboard/mixins/resize.js b/UI source code/dns_mapping_ui-master/src/views/dashboard/mixins/resize.js new file mode 100644 index 0000000..234953b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/dashboard/mixins/resize.js @@ -0,0 +1,55 @@ +import { debounce } from '@/utils' + +export default { + data() { + return { + $_sidebarElm: null, + $_resizeHandler: null + } + }, + mounted() { + this.$_resizeHandler = debounce(() => { + if (this.chart) { + this.chart.resize() + } + }, 100) + this.$_initResizeEvent() + this.$_initSidebarResizeEvent() + }, + beforeDestroy() { + this.$_destroyResizeEvent() + this.$_destroySidebarResizeEvent() + }, + // to fixed bug when cached by keep-alive + // https://github.com/PanJiaChen/vue-element-admin/issues/2116 + activated() { + this.$_initResizeEvent() + this.$_initSidebarResizeEvent() + }, + deactivated() { + this.$_destroyResizeEvent() + this.$_destroySidebarResizeEvent() + }, + methods: { + // use $_ for mixins properties + // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential + $_initResizeEvent() { + window.addEventListener('resize', this.$_resizeHandler) + }, + $_destroyResizeEvent() { + window.removeEventListener('resize', this.$_resizeHandler) + }, + $_sidebarResizeHandler(e) { + if (e.propertyName === 'width') { + this.$_resizeHandler() + } + }, + $_initSidebarResizeEvent() { + this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0] + this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) + }, + $_destroySidebarResizeEvent() { + this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) + } + } +} diff --git a/UI source code/dns_mapping_ui-master/src/views/features/401.vue b/UI source code/dns_mapping_ui-master/src/views/features/401.vue new file mode 100644 index 0000000..8a3b69e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/features/401.vue @@ -0,0 +1,89 @@ +<template> + <div class="errPage-container"> + <el-button icon="arrow-left" class="pan-back-btn" @click="back"> + 返回 + </el-button> + <el-row> + <el-col :span="12"> + <h1 class="text-jumbo text-ginormous"> + Oops! + </h1> + <h2>你没有权限去该页面</h2> + <h6>如有不满请联系你领导</h6> + <ul class="list-unstyled"> + <li>或者你可以去:</li> + <li class="link-type"> + <router-link to="/dashboard"> + 回首页 + </router-link> + </li> + </ul> + </el-col> + <el-col :span="12"> + <img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream."> + </el-col> + </el-row> + </div> +</template> + +<script> +import errGif from '@/assets/401_images/401.gif' + +export default { + name: 'Page401', + data() { + return { + errGif: errGif + '?' + +new Date() + } + }, + methods: { + back() { + if (this.$route.query.noGoBack) { + this.$router.push({ path: '/dashboard' }) + } else { + this.$router.go(-1) + } + } + } +} +</script> + +<style lang="scss" scoped> + .errPage-container { + width: 800px; + max-width: 100%; + margin: 100px auto; + .pan-back-btn { + background: #008489; + color: #fff; + border: none!important; + } + .pan-gif { + margin: 0 auto; + display: block; + } + .pan-img { + display: block; + margin: 0 auto; + width: 100%; + } + .text-jumbo { + font-size: 60px; + font-weight: 700; + color: #484848; + } + .list-unstyled { + font-size: 14px; + li { + padding-bottom: 5px; + } + a { + color: #008489; + text-decoration: none; + &:hover { + text-decoration: underline; + } + } + } + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/features/404.vue b/UI source code/dns_mapping_ui-master/src/views/features/404.vue new file mode 100644 index 0000000..237d81f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/features/404.vue @@ -0,0 +1,225 @@ +<template> + <div class="wscn-http404-container"> + <div class="wscn-http404"> + <div class="pic-404"> + <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404"> + <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404"> + <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404"> + <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404"> + </div> + <div class="bullshit"> + <div class="bullshit__oops">OOPS!</div> + <div class="bullshit__headline">{{ message }}</div> + <div class="bullshit__info">请检查您输入的网址是否正确,请点击以下按钮返回主页或者发送错误报告</div> + <a href="/" class="bullshit__return-home">返回首页</a> + </div> + </div> + </div> +</template> + +<script> + +export default { + name: 'Page404', + computed: { + message() { + return '网管说这个页面你不能进......' + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> +.wscn-http404-container{ + transform: translate(-50%,-50%); + position: absolute; + top: 40%; + left: 50%; +} +.wscn-http404 { + position: relative; + width: 1200px; + padding: 0 50px; + overflow: hidden; + .pic-404 { + position: relative; + float: left; + width: 600px; + overflow: hidden; + &__parent { + width: 100%; + } + &__child { + position: absolute; + &.left { + width: 80px; + top: 17px; + left: 220px; + opacity: 0; + animation-name: cloudLeft; + animation-duration: 2s; + animation-timing-function: linear; + animation-fill-mode: forwards; + animation-delay: 1s; + } + &.mid { + width: 46px; + top: 10px; + left: 420px; + opacity: 0; + animation-name: cloudMid; + animation-duration: 2s; + animation-timing-function: linear; + animation-fill-mode: forwards; + animation-delay: 1.2s; + } + &.right { + width: 62px; + top: 100px; + left: 500px; + opacity: 0; + animation-name: cloudRight; + animation-duration: 2s; + animation-timing-function: linear; + animation-fill-mode: forwards; + animation-delay: 1s; + } + @keyframes cloudLeft { + 0% { + top: 17px; + left: 220px; + opacity: 0; + } + 20% { + top: 33px; + left: 188px; + opacity: 1; + } + 80% { + top: 81px; + left: 92px; + opacity: 1; + } + 100% { + top: 97px; + left: 60px; + opacity: 0; + } + } + @keyframes cloudMid { + 0% { + top: 10px; + left: 420px; + opacity: 0; + } + 20% { + top: 40px; + left: 360px; + opacity: 1; + } + 70% { + top: 130px; + left: 180px; + opacity: 1; + } + 100% { + top: 160px; + left: 120px; + opacity: 0; + } + } + @keyframes cloudRight { + 0% { + top: 100px; + left: 500px; + opacity: 0; + } + 20% { + top: 120px; + left: 460px; + opacity: 1; + } + 80% { + top: 180px; + left: 340px; + opacity: 1; + } + 100% { + top: 200px; + left: 300px; + opacity: 0; + } + } + } + } + .bullshit { + position: relative; + float: left; + width: 300px; + padding: 30px 0; + overflow: hidden; + &__oops { + font-size: 32px; + font-weight: bold; + line-height: 40px; + color: #1482f0; + opacity: 0; + margin-bottom: 20px; + animation-name: slideUp; + animation-duration: 0.5s; + animation-fill-mode: forwards; + } + &__headline { + font-size: 20px; + line-height: 24px; + color: #222; + font-weight: bold; + opacity: 0; + margin-bottom: 10px; + animation-name: slideUp; + animation-duration: 0.5s; + animation-delay: 0.1s; + animation-fill-mode: forwards; + } + &__info { + font-size: 13px; + line-height: 21px; + color: grey; + opacity: 0; + margin-bottom: 30px; + animation-name: slideUp; + animation-duration: 0.5s; + animation-delay: 0.2s; + animation-fill-mode: forwards; + } + &__return-home { + display: block; + float: left; + width: 110px; + height: 36px; + background: #1482f0; + border-radius: 100px; + text-align: center; + color: #ffffff; + opacity: 0; + font-size: 14px; + line-height: 36px; + cursor: pointer; + animation-name: slideUp; + animation-duration: 0.5s; + animation-delay: 0.3s; + animation-fill-mode: forwards; + } + @keyframes slideUp { + 0% { + transform: translateY(60px); + opacity: 0; + } + 100% { + transform: translateY(0); + opacity: 1; + } + } + } +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/features/redirect.vue b/UI source code/dns_mapping_ui-master/src/views/features/redirect.vue new file mode 100644 index 0000000..db4c1d6 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/features/redirect.vue @@ -0,0 +1,12 @@ +<script> +export default { + created() { + const { params, query } = this.$route + const { path } = params + this.$router.replace({ path: '/' + path, query }) + }, + render: function(h) { + return h() // avoid warning message + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/views/generator/config.vue b/UI source code/dns_mapping_ui-master/src/views/generator/config.vue new file mode 100644 index 0000000..2690dd5 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/generator/config.vue @@ -0,0 +1,325 @@ +<template> + <div class="app-container"> + <el-row :gutter="15"> + <el-col style="margin-bottom: 10px"> + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">字段配置:{{ tableName }}</span> + <el-button + :loading="genLoading" + icon="el-icon-s-promotion" + size="mini" + style="float: right; padding: 6px 9px;" + type="success" + @click="toGen" + >保存&生成</el-button> + <el-button + :loading="columnLoading" + icon="el-icon-check" + size="mini" + style="float: right; padding: 6px 9px;margin-right: 9px" + type="primary" + @click="saveColumnConfig" + >保存</el-button> + <el-tooltip class="item" effect="dark" content="数据库中表字段变动时使用该功能" placement="top-start"> + <el-button + :loading="syncLoading" + icon="el-icon-refresh" + size="mini" + style="float: right; padding: 6px 9px;" + type="info" + @click="sync" + >同步</el-button> + </el-tooltip> + </div> + <el-form size="small" label-width="90px"> + <el-table v-loading="loading" :data="data" :max-height="tableHeight" size="small" style="width: 100%;margin-bottom: 15px"> + <el-table-column prop="columnName" label="字段名称" /> + <el-table-column prop="columnType" label="字段类型" /> + <el-table-column prop="remark" label="字段描述"> + <template slot-scope="scope"> + <el-input v-model="data[scope.$index].remark" size="mini" class="edit-input" /> + </template> + </el-table-column> + <el-table-column align="center" label="必填" width="70px"> + <template slot-scope="scope"> + <el-checkbox v-model="data[scope.$index].notNull" /> + </template> + </el-table-column> + <el-table-column align="center" label="列表" width="70px"> + <template slot-scope="scope"> + <el-checkbox v-model="data[scope.$index].listShow" /> + </template> + </el-table-column> + <el-table-column align="center" label="表单" width="70px"> + <template slot-scope="scope"> + <el-checkbox v-model="data[scope.$index].formShow" /> + </template> + </el-table-column> + <el-table-column label="表单类型"> + <template slot-scope="scope"> + <el-select v-model="data[scope.$index].formType" filterable class="edit-input" clearable size="mini" placeholder="请选择"> + <el-option + label="文本框" + value="Input" + /> + <el-option + label="文本域" + value="Textarea" + /> + <el-option + label="单选框" + value="Radio" + /> + <el-option + label="下拉框" + value="Select" + /> + <el-option + label="日期框" + value="Date" + /> + </el-select> + </template> + </el-table-column> + <el-table-column label="查询方式"> + <template slot-scope="scope"> + <el-select v-model="data[scope.$index].queryType" filterable class="edit-input" clearable size="mini" placeholder="请选择"> + <el-option + label="=" + value="=" + /> + <el-option + label="!=" + value="!=" + /> + <el-option + label=">=" + value=">=" + /> + <el-option + label="<=" + value="<=" + /> + <el-option + label="Like" + value="Like" + /> + <el-option + label="NotNull" + value="NotNull" + /> + <el-option + label="BetWeen" + value="BetWeen" + /> + </el-select> + </template> + </el-table-column> + <el-table-column label="日期注解"> + <template slot-scope="scope"> + <el-select v-model="data[scope.$index].dateAnnotation" filterable class="edit-input" clearable size="mini" placeholder="请选择"> + <el-option + label="自动创建时间" + value="CreationTimestamp" + /> + <el-option + label="自动更新时间" + value="UpdateTimestamp" + /> + </el-select> + </template> + </el-table-column> + <el-table-column label="关联字典"> + <template slot-scope="scope"> + <el-select v-model="data[scope.$index].dictName" filterable class="edit-input" clearable size="mini" placeholder="请选择"> + <el-option v-for="item in dicts" :key="item.id" :label="item.remark === '' ? item.name : item.remark" :value="item.name" /> + </el-select> + </template> + </el-table-column> + </el-table> + </el-form> + </el-card> + </el-col> + <el-col> + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">生成配置</span> + <el-button + :loading="configLoading" + icon="el-icon-check" + size="mini" + style="float: right; padding: 6px 9px" + type="primary" + @click="doSubmit" + >保存</el-button> + </div> + <el-form ref="form" :model="form" :rules="rules" size="small" label-width="78px"> + <el-form-item label="作者名称" prop="author"> + <el-input v-model="form.author" style="width: 40%" /> + <span style="color: #C0C0C0;margin-left: 10px;">类上面的作者名称</span> + </el-form-item> + <el-form-item label="模块名称" prop="moduleName"> + <el-input v-model="form.moduleName" style="width: 40%" /> + <span style="color: #C0C0C0;margin-left: 10px;">模块的名称,请选择项目中已存在的模块</span> + </el-form-item> + <el-form-item label="至于包下" prop="pack"> + <el-input v-model="form.pack" style="width: 40%" /> + <span style="color: #C0C0C0;margin-left: 10px;">项目包的名称,生成的代码放到哪个包里面</span> + </el-form-item> + <el-form-item label="接口名称" prop="apiAlias"> + <el-input v-model="form.apiAlias" style="width: 40%" /> + <span style="color: #C0C0C0;margin-left: 10px;">接口的名称,用于控制器与接口文档中</span> + </el-form-item> + <el-form-item label="前端路径" prop="path"> + <el-input v-model="form.path" style="width: 40%" /> + <span style="color: #C0C0C0;margin-left: 10px;">输入views文件夹下的目录,不存在即创建</span> + </el-form-item> + <!-- <el-form-item label="接口目录">--> + <!-- <el-input v-model="form.apiPath" style="width: 40%" />--> + <!-- <span style="color: #C0C0C0;margin-left: 10px;">Api存放路径[src/api],为空则自动生成路径</span>--> + <!-- </el-form-item>--> + <el-form-item label="去表前缀" prop="prefix"> + <el-input v-model="form.prefix" placeholder="默认不去除表前缀" style="width: 40%" /> + <span style="color: #C0C0C0;margin-left: 10px;">默认不去除表前缀,可自定义</span> + </el-form-item> + <el-form-item label="是否覆盖" prop="cover"> + <el-radio-group v-model="form.cover" size="mini" style="width: 40%"> + <el-radio-button label="true">是</el-radio-button> + <el-radio-button label="false">否</el-radio-button> + </el-radio-group> + <span style="color: #C0C0C0;margin-left: 10px;">谨防误操作,请慎重选择</span> + </el-form-item> + </el-form> + </el-card> + </el-col> + </el-row> + </div> +</template> + +<script> +import crud from '@/mixins/crud' +import { update, get } from '@/api/generator/genConfig' +import { save, sync, generator } from '@/api/generator/generator' +import { getDicts } from '@/api/system/dict' +export default { + name: 'GeneratorConfig', + components: {}, + mixins: [crud], + data() { + return { + activeName: 'first', tableName: '', tableHeight: 550, columnLoading: false, configLoading: false, dicts: [], syncLoading: false, genLoading: false, + form: { id: null, tableName: '', author: '', pack: '', path: '', moduleName: '', cover: 'false', apiPath: '', prefix: '', apiAlias: null }, + rules: { + author: [ + { required: true, message: '作者不能为空', trigger: 'blur' } + ], + pack: [ + { required: true, message: '包路径不能为空', trigger: 'blur' } + ], + moduleName: [ + { required: true, message: '包路径不能为空', trigger: 'blur' } + ], + path: [ + { required: true, message: '前端路径不能为空', trigger: 'blur' } + ], + apiAlias: [ + { required: true, message: '接口名称不能为空', trigger: 'blur' } + ], + cover: [ + { required: true, message: '不能为空', trigger: 'blur' } + ] + } + } + }, + created() { + this.tableHeight = document.documentElement.clientHeight - 385 + this.tableName = this.$route.params.tableName + this.$nextTick(() => { + this.init() + get(this.tableName).then(data => { + this.form = data + this.form.cover = this.form.cover.toString() + }) + getDicts().then(data => { + this.dicts = data + }) + }) + }, + methods: { + beforeInit() { + this.url = 'api/generator/columns' + const tableName = this.tableName + this.params = { tableName } + return true + }, + saveColumnConfig() { + this.columnLoading = true + save(this.data).then(res => { + this.notify('保存成功', 'success') + this.columnLoading = false + }).catch(err => { + this.columnLoading = false + console.log(err.response.data.message) + }) + }, + doSubmit() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.configLoading = true + update(this.form).then(res => { + this.notify('保存成功', 'success') + this.form = res + this.form.cover = this.form.cover.toString() + this.configLoading = false + }).catch(err => { + this.configLoading = false + console.log(err.response.data.message) + }) + } + }) + }, + sync() { + this.syncLoading = true + sync([this.tableName]).then(() => { + this.init() + this.notify('同步成功', 'success') + this.syncLoading = false + }).then(() => { + this.syncLoading = false + }) + }, + toGen() { + this.genLoading = true + save(this.data).then(res => { + this.notify('保存成功', 'success') + // 生成代码 + generator(this.tableName, 0).then(data => { + this.genLoading = false + this.notify('生成成功', 'success') + }).catch(err => { + this.genLoading = false + console.log(err.response.data.message) + }) + }).catch(err => { + this.genLoading = false + console.log(err.response.data.message) + }) + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss"> + .edit-input { + .el-input__inner { + border: 1px solid #e5e6e7; + } + } +</style> + +<style scoped> + ::v-deep .input-with-select .el-input-group__prepend { + background-color: #fff; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/generator/index.vue b/UI source code/dns_mapping_ui-master/src/views/generator/index.vue new file mode 100644 index 0000000..6a07dc4 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/generator/index.vue @@ -0,0 +1,114 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <el-input v-model="query.name" clearable size="small" placeholder="请输入表名" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <rrOperation /> + </div> + <crudOperation> + <el-tooltip slot="right" class="item" effect="dark" content="数据库中表字段变动时使用该功能" placement="top-start"> + <el-button + class="filter-item" + size="mini" + type="success" + icon="el-icon-refresh" + :loading="syncLoading" + :disabled="crud.selections.length === 0" + @click="sync" + >同步</el-button> + </el-tooltip> + </crudOperation> + </div> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> + <el-table-column type="selection" width="55" /> + <el-table-column :show-overflow-tooltip="true" prop="tableName" label="表名" /> + <el-table-column :show-overflow-tooltip="true" prop="engine" label="数据库引擎" /> + <el-table-column :show-overflow-tooltip="true" prop="coding" label="字符编码集" /> + <el-table-column :show-overflow-tooltip="true" prop="remark" label="备注" /> + <el-table-column prop="createTime" label="创建日期" /> + <el-table-column label="操作" width="160px" align="center" fixed="right"> + <template slot-scope="scope"> + <el-button size="mini" style="margin-right: 2px" type="text"> + <router-link :to="'/sys-tools/generator/preview/' + scope.row.tableName"> + 预览 + </router-link> + </el-button> + <el-button size="mini" style="margin-left: -1px;margin-right: 2px" type="text" @click="toDownload(scope.row.tableName)">下载</el-button> + <el-button size="mini" style="margin-left: -1px;margin-right: 2px" type="text"> + <router-link :to="'/sys-tools/generator/config/' + scope.row.tableName"> + 配置 + </router-link> + </el-button> + <el-button type="text" style="margin-left: -1px" size="mini" @click="toGen(scope.row.tableName)">生成</el-button> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> + +import { generator, sync } from '@/api/generator/generator' +import { downloadFile } from '@/utils/index' +import CRUD, { presenter, header } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import pagination from '@crud/Pagination' + +export default { + name: 'GeneratorIndex', + components: { pagination, crudOperation, rrOperation }, + cruds() { + return CRUD({ url: 'api/generator/tables' }) + }, + mixins: [presenter(), header()], + data() { + return { + syncLoading: false + } + }, + created() { + this.crud.optShow = { add: false, edit: false, del: false, download: false } + }, + methods: { + toGen(tableName) { + // 生成代码 + generator(tableName, 0).then(data => { + this.$notify({ + title: '生成成功', + type: 'success', + duration: 2500 + }) + }) + }, + toDownload(tableName) { + // 打包下载 + generator(tableName, 2).then(data => { + downloadFile(data, tableName, 'zip') + }) + }, + sync() { + const tables = [] + this.crud.selections.forEach(val => { + tables.push(val.tableName) + }) + this.syncLoading = true + sync(tables).then(() => { + this.crud.refresh() + this.crud.notify('同步成功', CRUD.NOTIFICATION_TYPE.SUCCESS) + this.syncLoading = false + }).then(() => { + this.syncLoading = false + }) + } + } +} +</script> + +<style scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/generator/preview.vue b/UI source code/dns_mapping_ui-master/src/views/generator/preview.vue new file mode 100644 index 0000000..e95fc46 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/generator/preview.vue @@ -0,0 +1,30 @@ +<template> + <el-tabs v-model="activeName" type="card"> + <el-tab-pane v-for="item in data" :key="item.name" :lazy="true" :label="item.name" :name="item.name"> + <Java :value="item.content" :height="height" /> + </el-tab-pane> + </el-tabs> +</template> + +<script> +import Java from '@/components/JavaEdit/index' +import { generator } from '@/api/generator/generator' +export default { + name: 'Preview', + components: { Java }, + data() { + return { + data: null, height: '', activeName: 'Entity' + } + }, + created() { + this.height = document.documentElement.clientHeight - 180 + 'px' + const tableName = this.$route.params.tableName + generator(tableName, 1).then(data => { + this.data = data + }).catch(() => { + this.$router.go(-1) + }) + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/views/home.vue b/UI source code/dns_mapping_ui-master/src/views/home.vue new file mode 100644 index 0000000..7093881 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/home.vue @@ -0,0 +1,1074 @@ +<template> + <div class="dashboard-container"> + <div class="form_list"> + <div style="width: 100%; background-color: #fff"> + <div class="form_title"> + <div :class="tabshow == 1 ? 'active' : ''" @click="tab(1)"> + <i class="el-icon-date" />服务数据 + </div> + <div :class="tabshow == 2 ? 'active' : ''" @click="tab(2)"> + <i class="el-icon-picture-outline" />网络数据 + </div> + <div :class="tabshow == 3 ? 'active' : ''" @click="tab(3)"> + <i class="el-icon-notebook-2" />主机数据 + </div> + </div> + <div class="middle"> + <!-- 父盒子 --> + <div class="father_box"> + <div class="sea_box" @click="onclick()"> + <div + v-for="(item, index) in keyword" + :key="index" + ref="Tag" + :class="index % 2 != 0 ? 'spanbox_value' : 'spanbox_key'" + > + <span v-if="Array.isArray(item)" class="tagspan"> + <span v-for="(a,i) in item" :key="i">{{ a[a.length-1] }}</span> + </span> + <span v-else class="tagspan">{{ item }}</span> + <i + v-if="index % 2 != 0" + class="span_close" + @click="removeTag(index, item)" + /> + </div> + <el-input + v-if="type === 'input'" + ref="inputTag" + v-model="currentval" + placeholder="请输入检索内容" + :style="inputStyle" + class="inputTag" + type="text" + @keydown.native="handleKeydown" + @focus="searchFoucs" + /> + <el-select + v-else-if="type == 'select'" + ref="inputTag" + v-model="currentval" + placeholder="请输入检索内容" + :style="inputStyle" + class="inputTag" + type="text" + filterable + remote + default-first-option + @change="addTags" + @keyup.native="handleKeydown" + @focus="searchFoucs" + > + <el-option + v-for="item in options" + :key="item.value" + :label="item.label" + :value="item.value" + :disabled="item.disabled" + /> + </el-select> + + <el-cascader + v-else-if="type == 'more'" + ref="inputTag" + v-model="currentval" + :options="options" + :props="{ multiple: true, checkStrictly: true }" + clearable + :style="inputStyle" + class="inputTag" + type="text" + filterable + remote + default-first-option + @change="addTags" + @keyup.native="handleKeydown" + @focus="searchFoucs" + /> + + <el-select + v-else + ref="inputTag" + v-model="currentval" + placeholder="请输入检索内容" + :style="inputStyle" + class="inputTag" + type="text" + filterable + remote + default-first-option + @change="addTags" + @keyup.native="handleKeydown" + @focus="searchFoucs" + > + <el-option + v-for="item in options" + :key="item.value" + :label="item.label" + :value="item.value" + :disabled="item.disabled" + /> + </el-select> + </div> + </div> + <!-- 搜索按钮 --> + <el-row> + <el-button + type="primary" + @click="search" + >搜 索</el-button> + </el-row> + <!-- </el-form> --> + <div class="text"> + <p class="massage"> + 共<i v-if="loging" class="el-icon-loading" /> + <span v-if="!loging">{{ list.resultTotal }}</span>条,含<i v-if="loging" class="el-icon-loading" /> + <span v-if="!loging"> + {{ handleIndependIpNum(list.independentIpNum) }}</span> + + 个独立IP,<i v-if="loging" class="el-icon-loading" /><span + v-if="!loging" + class="second" + >用时{{ list.totalTime }}秒</span> + </p> + <div class="switch"> + <el-switch v-model="value1" inactive-text="排除蜜罐" /> + <el-switch v-model="value2" inactive-text="数据去重" /> + <el-switch v-model="value3" inactive-text="排除CDN" /> + <el-switch v-model="value4" inactive-text="最新数据" /> + </div> + </div> + </div> + </div> + <div class="form_box"> + <!-- 内容 --> + <div v-show="tabshow == 1"> + <Sreviceleft v-if="leftShow" v-loading.lock="loging" /> + <SreviceRight v-if="rightShow" v-loading.lock="loging" /> + <div class="clear" /> + <!-- 分页 --> + <div class="block"> + <el-pagination + v-if="pageShow" + :page-sizes="[10, 20, 30, 40]" + :page-size="size" + layout="total, sizes, prev, pager, next, jumper" + :total="list.resultTotal" + @size-change="handleSizeChange" + @current-change="curPage" + /> + </div> + <!-- <Foot /> --> + <!-- <pagination/> --> + </div> + <div v-show="tabshow == 2" /> + <div v-show="tabshow == 3">3</div> + </div> + </div> + <!-- 返回顶部 --> + <div class="top"> + <span + v-if="btnFlag" + class="backtop" + @click="toTop" + ><i + class="el-icon-top" + /></span> + </div> + </div> +</template> + +<script> +import Sreviceleft from '../components/Search/left.vue' +import SreviceRight from '../components/Search/right.vue' +import { mapActions, mapGetters } from 'vuex' +import fackClickOutSide from '@/utils/fackClickOutSide' +// import Search from "../components/SearchInput/SearchInput.vue"; + +export default { + mixins:[fackClickOutSide], + name: 'InputTags', + components: { + Sreviceleft, + SreviceRight + // Search, + }, + props: { + parentArr: { + type: Array, + default() { + return ['service', 'dns-doh'] + } + }, + limit: { + type: Number + } + }, + data() { + return { + tabshow: 1, + value1: false, + value2: false, + value3: false, + value4: false, + pageShow: true, + rightShow: true, + leftShow: true, + btnFlag: false, // 返回顶部 + // 搜索框 + keyword: [], + obj: { service: 'dns-doh' }, + obj1: [], + currentval: '', + inputLength: '', + // nav_list: true, + // // Loading: false, + // Loadshow: false, + options: [], + options1: [{ + value: 'service', + label: 'service', + disabled: false + }, + { + value: 'ip', + label: 'ip', + disabled: false + }, + { + value: 'port', + label: 'port', + disabled: false + }], + // options3: [ { + // value: "dns-doh", + // label: "dns-doh", + // disabled: false + // }, + // { + // value: "dns-do53", + // label: "dns-do53", + // disabled: false + // },], + options2: [ + { + value: 'DNS', + label: 'DNS', + disabled: false, + children: [ + { + value: 'dns-doh', + label: 'dns-doh', + disabled: false + // children: [ + // { + // value: "proxy", + // label: "proxy", + // disabled: false, + // }, + // { + // value: "server", + // label: "server", + // disabled: false, + // }, + // ], + + }, + { + value: 'dns-do53', + label: 'dns-do53', + disabled: false + // children: [ + // { + // value: "open-rdns", + // label: "open-rdns", + // disabled: false, + // }, + // { + // value: "egress-dns", + // label: "egress-dns", + // disabled: false, + // }, + // { + // value: "forwarder", + // label: "forwarder", + // disabled: false, + // }, + // { + // value: "fwd/rdns", + // label: "fwd/rdns", + // disabled: false, + // }, + // { + // value: "nonstandard", + // label: "nonstandard", + // disabled: false, + // }, + // { + // value: "root", + // label: "root", + // disabled: false, + // }, + // { + // value: "tld", + // label: "tld", + // disabled: false, + // }, + // { + // value: "ns", + // label: "ns", + // disabled: false, + // }, + // ], + } + ] + } + // { + // value: "email", + // label: "email", + // disabled: false, + // children: [ + // { + // value: "email-1", + // label: "email-1", + // disabled: false, + // }, + // { + // value: "email-2", + // label: "email-2", + // disabled: false, + // }, + // ], + // }, + ], + isFocus: false, + type: 'select', + newSer: [], + newip: [], + newPort: [], + find: { service: 'dns-doh' } + } + }, + watch: { + keyword() { + this.$emit('on-change', this.keyword) + }, + currentval(val) { + this.inputLength = this.$refs.inputTag.value.length * 12 + 50 + }, + parentArr() { + this.keyword = this.parentArr.length ? this.parentArr : [] + } + }, + created() { + window.addEventListener('scroll', this.scrollToTop) + // this.enterSearch(); + + // document.addEventListener('click', (e) => { + // var nav = document.getElementsByClassName('listhide')[0] + // if (nav.contains(e.target)) { + // this.nav_list = true + // } else { + // this.nav_list = false + // } + // }) + }, + destroyed() { + window.removeEventListener('scroll', () => { + this.scrollToTop() + }) + }, + computed: { + ...mapGetters({ + list: 'searchlist/list', + size: 'searchlist/size', + left: 'searchlist/left', + // xylist: 'searchlist/xylist', + loging: 'searchlist/Loging' + }), + inputStyle() { + const style = {} + style.width = `${this.inputLength}px` + return style + }, + finall() { + return this.keyword.join(',') + } + }, + + methods: { + // 删除 + removeTag(index, item) { + // console.log(index, item); + this.keyword.splice(index, 1) + this.keyword.splice(index - 1, 1) + this.update() + // this.gs() + for (var i = 0; i < this.obj1.length; i++) { + if (item == this.obj1[i].service || item == this.obj1[i].ip || item == this.obj1[i].port) { + // console.log(this.obj1[i].service,i) + this.obj1.splice(i, 1) + i-- + } + } + this.concat() + // this.contrast(this.newSer,item) + // this.contrast(this.newip,item) + // this.contrast(this.newPort,item) + // console.log(this.newSer,this.newip,this.newPort,"---del") + }, + // 比较 + // contrast(arr,item){ + // if(arr){ + // for(var i=0;i<arr.length;i++){ + // // console.log(arr[0],item,90); + // if(item == arr[i]){ + // return arr.splice(i,1) + // } + // } + // } + + // }, + edit() { + var str = [] + this.keyword.forEach(item => { + if (Array.isArray(item)) { + item.forEach(a => { + str.push(a[a.length - 1]) + }) + } else { + str.push(item) + } + }) + for (var i = 0; i < str.length; i++) { + if (str[i] == 'DNS') { + this.options2[this.options2.findIndex((item) => item.value === 'DNS')].disabled = true + for (var a = 0; a < this.options2.length; a++) { + if (this.options2[a].children) { + for (var j = 0; j < this.options2[a].children.length; j++) { + this.$set(this.options2[a].children[j], 'disabled', true) + if (this.options2[a].children[j].children) { + for (var b = 0; b < this.options2[a].children[j].children.length; b++) { + this.$set(this.options2[a].children[j].children[b], 'disabled', true) + } + } + } + } + } + } else if (str[i] == 'dns-doh') { + var text1 = this.options2[this.options2.findIndex((item) => item.value === 'DNS')].children + text1[text1.findIndex((item) => item.value === 'dns-doh')].disabled = true + for (var a = 0; a < text1.length; a++) { + if (text1[a].children) { + for (var b = 0; b < text1[a].children.length; b++) { + this.$set(text1[a].children[b], 'disabled', true) + } + } + } + } else if (str[i] == 'dns-do53') { + var text1 = this.options2[this.options2.findIndex((item) => item.value === 'DNS')].children + text1[text1.findIndex((item) => item.value === 'dns-do53')].disabled = true + for (var a = 0; a < text1.length; a++) { + if (text1[a].children) { + for (var b = 0; b < text1[a].children.length; b++) { + this.$set(text1[a].children[b], 'disabled', true) + } + } + } + } + } + }, + update() { + this.options2.forEach(item => { + this.$set(item, 'disabled', false) + if (item.children) { + item.children.forEach(a => { + this.$set(a, 'disabled', false) + if (a.children) { + a.children.forEach(b => { + this.$set(b, 'disabled', false) + }) + } + }) + } + }) + }, + addTags(e) { + // console.log(this.currentval,e, "code输入"); + // console.log(this.options1, this.options2, "下拉列表"); + if (this.currentval != '') { + if (this.currentval == 'service') { + this.options = this.options2 + this.type = 'more' + this.keyword.push(this.currentval) + this.currentval = '' + } else if (this.currentval == 'ip' || this.currentval == 'port') { + this.type = 'input' + this.keyword.push(this.currentval) + this.currentval = '' + } else { + this.options = this.options1 + this.type = 'select' + this.keyword.push(this.currentval) + this.currentval = '' + } + // console.log(this.keyword); + this.edit() + this.concat() + } + }, + // 拼接格式 + concat() { + var str = [] + this.keyword.forEach(item => { + if (Array.isArray(item)) { + item.forEach(a => { + str.push(a[a.length - 1]) + }) + } else { + str.push(item) + } + }) + var ser = [] + var ip = [] + var port = [] + for (var i = 1; i <= str.length / 2; i++) { + this.$set(this.obj, str[2 * i - 2], str[2 * i - 1]) + if (str[2 * i - 2] == 'service') { + ser.push(str[2 * i - 1]) + } else if (str[2 * i - 2] == 'ip') { + ip.push(str[2 * i - 1]) + } else if (str[2 * i - 2] == 'port') { + port.push(str[2 * i - 1]) + } + } + this.newSer = this.delRepeat(ser) + this.newip = this.delRepeat(ip) + this.newPort = this.delRepeat(port) + var serArr = this.newSer.join(' AND ') + var ipArr = this.newip.join(' AND ') + var portArr = this.newPort.join(' AND ') + this.$set(this.find, 'service', serArr) + this.$set(this.find, 'ip', ipArr) + this.$set(this.find, 'port', portArr) + // console.log(this.obj1,"1111"); + console.log(this.find) + }, + // 去重 + delRepeat(arr) { + const newArr = [] + for (let i = 0; i < arr.length; i++) { + let flag = true + for (let j = 0; j < newArr.length; j++) { + arr[i] === newArr[j] ? flag = false : flag + } + flag ? newArr.push(arr[i]) : newArr + } + return newArr + }, + handleKeydown(e) { + console.log(e); + var keyCode = window.event ? e.keyCode : e.which + this.$nextTick(() => { + if (keyCode === 8) { + // console.log(this.$refs.inputTag.value,'----value'); + // console.log(this.$refs.inputTag.query,'----query'); + // console.log(this.currentval,'cur'); + + if (this.$refs.inputTag.query === '' || (this.currentval == '' && this.$refs.inputTag.query == undefined)) { + setTimeout(() => { + // console.log(888); + this.keyword.pop() + this.searchFoucs() + }) + } + } + if (keyCode == 13) { + if (this.type == 'input') { + // console.log(this.$refs.inputTag,this.type,this.currentval,898); + // this.$refs.inputTag.visible = false; + setTimeout(() => { + this.addTags() + this.search() + }) + } else if (this.type == 'select' && this.keyword.length % 2 === 0) { + setTimeout(() => { + this.addTags() + // this.keyword.pop(); + this.search() + }) + } + } + }) + }, + onclick() { + this.$nextTick(() => { + this.$refs.inputTag.focus(); + this.searchFoucs() + // this.redit() + }) + }, + // 输入框键盘删除键删除tag + // deleteTags(state) { + // var keyCode = window.event ? e.keyCode : e.which; + // if (state) { + // setTimeout(() => { + // this.keyword.pop(); + // this.searchFoucs(); + // }); + // } + // }, + // changeArr(arr) { + // var item = {}; + // // arr = arr.toString().split(""); + // for (var i = 0; i < arr.length; i++) { + // var dt = arr[i]; + // if (item[dt]) { + // item[dt]++; + // } else { + // item[dt] = 1; + // } + // } + // return item; + // }, + searchFoucs() { + var str = [] + this.keyword.forEach(item => { + if (Array.isArray(item)) { + item.forEach(a => { + str.push(a[a.length - 1]) + }) + } else { + str.push(item) + } + }) + var len = str.length + var last = str[len - 1] + if (last == 'service') { + this.options = this.options2 + this.type = 'more' + } else if (last == 'ip' || last == 'port') { + this.type = 'input' + } else { + this.options = this.options1 + this.type = 'select' + } + this.update() + this.edit() + }, + ...mapActions({ + listActions: 'searchlist/listActions', + leftlistActions: 'searchlist/leftlistActions', + changePage: 'searchlist/pageActions', + changeSize: 'searchlist/sizeActions' + }), + + // 搜索点击方法 + search() { + this.addTags() + this.concat() + this.leftlistActions(this.find) + this.curPage(1) + this.pageShow = false + this.rightShow = false; + (this.leftShow = false), + this.$nextTick(() => { + this.pageShow = true + this.rightShow = true + this.leftShow = true + }) + this.$store.state.searchlist.Loging = true + // console.log(this.obj,13); + }, + // 回车搜索 + // enterSearch() { + // document.onkeydown = (e) => { + // if (e.key === "Enter" && this.keyword.length % 2 ===0) { + // console.log("执行搜索", this.keyword.length % 2); + // this.search(); + // } + // }; + // }, + // 返回顶部 + toTop() { + window.scroll({ + top: 0, + left: 0, + behavior: 'smooth' + }) + }, + scrollToTop() { + const scrollTop = + window.pageYOffset || + document.documentElement.scrollTop || + document.body.scrollTop + const h = + window.innerHeight || + document.documentElement.clientHeight || + document.body.clientHeight + if (scrollTop > h) { + this.btnFlag = true + } else { + this.btnFlag = false + } + }, + // 分页 + curPage(page) { + this.changePage(page) + this.listActions(this.find) + this.$store.state.searchlist.Loging = true + }, + // 每页条数 + handleSizeChange(val) { + this.changeSize(val) + // this.listActions(this.obj); + this.listActions(this.find) + }, + // 选项卡切换 + tab(val) { + this.tabshow = val + }, + handleIndependIpNum(independentIpNum) { + if (!isNaN(independentIpNum)) { + return independentIpNum + } else { + // independentIpNum.forEach(a=>{ + // res += a.key + ':' + a.value + ',' + // }) + let val = JSON.stringify(independentIpNum) + val = val.substring(1, val.length - 1) + return val.replaceAll('\"', '') + } + } + }, + mounted() { + this.keyword = this.parentArr + this.listActions(this.find) + this.leftlistActions(this.find) + this.keyword = this.parentArr + this.options = this.options1 + // this.gs() + this.concat() + } +} +</script> + +<style lang="scss" scoped> +.dashboard-container { + // width: 91%; + // margin: 0px auto; + height: 100vh; + .form_list { + width: 100%; + padding-bottom: 20px; + background-color: #f9fafd; + .middle { + width: 91%; + margin: 0px auto; + background-color: white; + margin-bottom: 10px; + margin-top: 5px; + .el-button--primary { + background-color: #4608ad; + border-color: #4608ad; + } + } + .form_title { + width: 91%; + margin: 0px auto; + display: flex; + align-items: center; + height: 45px; + line-height: 45px; + text-align: center; + // margin-top: 10px; + // border: 1px solid transparent; + background-color: white; + div { + width: 180px; + padding-left: 5px; + background-color: #f9fafd; + border-radius: 10px 10px 0px 0px; + color: #000; + margin-right: 4px; + margin-top: 10px; + } + .active { + background-color: #4608ad; + color: white; + } + } + .form_box { + width: 91%; + margin: 0px auto; + } + .clear { + clear: both; + } + } + .search { + width: 100%; + height: 44px; + border: 1px solid #ccc; + border-radius: 0px 10px 10px 10px; + outline-style: none; + padding: 0; + } + .el-button--primary { + position: absolute; + right: 2px; + bottom: 4px; + height: 34px; + width: 132px; + font-size: 16px; + border-radius: 5px; + z-index: 1; + } + .text { + display: flex; + justify-content: space-between; + align-items: center; + .massage { + // background: palegreen; + width: 70%; + // float: left; + span { + color: #4608ad; + } + .second { + color: rgb(228, 107, 100); + } + } + .switch { + // background: pink; + // width: 30%; + // float: right; + margin: 16px 0px; + color: white !important; + div >>> .el-switch__label.is-active { + color: #ccc !important; + } + } + } + .backtop { + background-color: transparent; + border: 1px solid #4608ad; + border-radius: 50%; + text-align: center; + color: #4608ad; + } +} +@media only screen and (min-width: 768px) and (max-width: 1370px) { + .dashboard-container .text >>> .massage { + width: 60%; + } + .backtop { + position: fixed; + width: 40px; + height: 40px; + bottom: 40px; + right: 10px; + line-height: 40px; + } +} +@media only screen and (min-width: 1371px) and (max-width: 2400px) { + .dashboard-container .text >>> .massage { + width: 63%; + } + .backtop { + position: fixed; + width: 50px; + height: 50px; + bottom: 50px; + right: 20px; + line-height: 50px; + } +} +.el-select--small >>> .el-input--small .el-input__inner { + height: 44px !important; + border: 1px solid #ccc; + border-radius: 0px 10px 10px 10px; + outline-style: none; + padding: 0; + z-index: -3; +} +.block { + // display: flex; + // justify-content: flex-end; + float: right; + width: 76%; + height: 50px; + line-height: 50px; + background-color: #fff; +} +.block >>> .el-pagination { + height: 50px; + line-height: 50px; + padding: 10px 5px; + float: right; + .active { + color: #4608ad; + } +} +/* 外层div */ +.father_box { + .sea_box { + height: 40px; + line-height: 40px; + } + /* width: 300px; */ + box-sizing: border-box; + background-color: white; + border: 1px solid #7b68ee; + border-radius: 0px 8px 8px 8px; + font-size: 12px; + text-align: left; + padding-left: 5px; + word-wrap: break-word; + overflow: hidden; +} +/* 标签 */ +.key, +.value { + display: inline-block; + font-size: 14px; + margin: 3px 4px 3px 0; + background-color: rgb(229, 229, 229); + border: 1px solid #e8eaec; + border-radius: 3px; +} +// .spanbox { +// display: inline-block; +// font-size: 14px; +// margin: 3px 4px 3px 0; +// background-color: #e5e5e5; +// border: 1px solid #e8eaec; +// border-radius: 3px; +// height: 30px; +// line-height: 30px; +// } +.spanbox_value { + display: inline-block; + font-size: 14px; + margin: 6px 4px 3px 0; + background-color: #d9e4ff; + border: 1px solid #e8eaec; + border-radius: 3px; + height: 30px; + line-height: 30px; +} +.spanbox_key { + display: inline-block; + font-size: 14px; + margin: 6px 4px 3px 0; + background-color: #b5c8f8; + border: 1px solid #e8eaec; + border-radius: 3px; + height: 30px; + line-height: 30px; +} +.tagspan { + height: 24px; + line-height: 22px; + max-width: 100%; + position: relative; + display: inline-block; + padding-left: 8px; + padding-right: 8px; + color: #495060; + font-size: 14px; + cursor: pointer; + opacity: 1; + vertical-align: middle; + overflow: hidden; + transition: 0.25s linear; + color: #4608ad; + font-weight: 600; +} +.span_close { + padding: 0 4px 0 4px; + opacity: 1; + -webkit-filter: none; + filter: none; + color: #4608ad; + font-weight: 600; +} +.span_close:after { + content: "\00D7"; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + /* line-height: 27px; */ + transition: 0.3s, color 0s; +} +/* input */ +.inputTag { + font-size: 16px; + border: none; + box-shadow: none; + outline: none; + background-color: transparent; + padding: 0; + width: auto; + min-width: 250px; + vertical-align: top; + height: 32px; + color: #495060; + line-height: 32px; +} +.el-select--small >>> .el-input--small .el-input__inner { + border: none; +} +.el-select--small >>> .el-input--small .el-input__suffix { + display: none; +} +.el-cascader >>>.el-input--small .el-input__inner{ + border: none; +} +.el-cascader >>> .el-input--small .el-input__suffix { + display: none; +} +.el-cascader >>> .el-cascader__tags{ + margin-top: 5px; + font-size: 13px; + padding: 0px; +} +.el-cascader >>> .el-cascader__search-input{ + margin: 0px; +} +.el-input--small >>> .el-input__inner { + border: none; + margin-top: 5px; + font-size: 13px; + padding: 0px; +} +.nav_list { + position: relative; + width: 100%; + + ul { + box-shadow: 5px 5px 16px rgba(0, 0, 0, 0.1); + width: 100%; + position: absolute; + padding: 0px; + margin: 0px; + list-style: none; + background-color: white; + top: 0; + left: 0; + z-index: 1; + li { + display: inline-block; + width: 100%; + height: 30px; + line-height: 30px; + padding-left: 12px; + } + } +} +// .el-cascader__dropdown{ +// position: absolute !important; +// top: 174px !important; +// left: 324px !important; +// z-index: 1 !important; +// } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/login.vue b/UI source code/dns_mapping_ui-master/src/views/login.vue new file mode 100644 index 0000000..0622e3c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/login.vue @@ -0,0 +1,215 @@ +<template> + <div class="login" :style="'background-image:url('+ Background +');'"> + <el-form ref="loginForm" :model="loginForm" :rules="loginRules" label-position="left" label-width="0px" class="login-form"> + <h3 class="title"> + DiamondV 后台管理系统 + </h3> + <el-form-item prop="username"> + <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号"> + <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /> + </el-input> + </el-form-item> + <el-form-item prop="password"> + <el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码" @keyup.enter.native="handleLogin"> + <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" /> + </el-input> + </el-form-item> + <!-- <el-form-item prop="code"> + <el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter.native="handleLogin"> + <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" /> + </el-input> + <div class="login-code"> + <img :src="codeUrl" @click="getCode"> + </div> + </el-form-item> --> + <!-- <el-checkbox v-model="loginForm.rememberMe" style="margin:0 0 25px 0;"> + 记住我 + </el-checkbox> --> + <el-form-item style="width:100%;"> + <el-button :loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleLogin"> + <span v-if="!loading">登 录</span> + <span v-else>登 录 中...</span> + </el-button> + </el-form-item> + </el-form> + <!-- 底部 --> + <!-- <div v-if="$store.state.settings.showFooter" id="el-login-footer"> + <span v-html="$store.state.settings.footerTxt" /> + <span> ⋅ </span> + <a href="https://beian.miit.gov.cn/#/Integrated/index" target="_blank">{{ $store.state.settings.caseNumber }}</a> + </div> --> + </div> +</template> + +<script> +import { encrypt } from '@/utils/rsaEncrypt' +import Config from '@/settings' +import { getCodeImg } from '@/api/login' +import Cookies from 'js-cookie' +import qs from 'qs' +import Background from '@/assets/images/background.jpeg' +export default { + name: 'Login', + data() { + return { + Background: Background, + codeUrl: '', + cookiePass: '', + loginForm: { + username: 'admin', + password: '123456', + rememberMe: false, + code: '', + uuid: '' + }, + loginRules: { + username: [{ required: true, trigger: 'blur', message: '用户名不能为空' }], + password: [{ required: true, trigger: 'blur', message: '密码不能为空' }], + code: [{ required: true, trigger: 'change', message: '验证码不能为空' }] + }, + loading: false, + redirect: undefined + } + }, + watch: { + $route: { + handler: function(route) { + const data = route.query + if (data && data.redirect) { + this.redirect = data.redirect + delete data.redirect + if (JSON.stringify(data) !== '{}') { + this.redirect = this.redirect + '&' + qs.stringify(data, { indices: false }) + } + } + }, + immediate: true + } + }, + created() { + // 获取验证码 + this.getCode() + // 获取用户名密码等Cookie + this.getCookie() + // token 过期提示 + this.point() + }, + methods: { + getCode() { + getCodeImg().then(res => { + this.codeUrl = res.img + this.loginForm.uuid = res.uuid + }) + }, + getCookie() { + const username = Cookies.get('username') + let password = Cookies.get('password') + const rememberMe = Cookies.get('rememberMe') + // 保存cookie里面的加密后的密码 + this.cookiePass = password === undefined ? '' : password + password = password === undefined ? this.loginForm.password : password + this.loginForm = { + username: username === undefined ? this.loginForm.username : username, + password: password, + rememberMe: rememberMe === undefined ? false : Boolean(rememberMe), + code: '' + } + }, + handleLogin() { + this.$refs.loginForm.validate(valid => { + const user = { + username: this.loginForm.username, + password: this.loginForm.password, + rememberMe: this.loginForm.rememberMe, + code: this.loginForm.code, + uuid: this.loginForm.uuid + } + if (user.password !== this.cookiePass) { + user.password = encrypt(user.password) + } + if (valid) { + this.loading = true + if (user.rememberMe) { + Cookies.set('username', user.username, { expires: Config.passCookieExpires }) + Cookies.set('password', user.password, { expires: Config.passCookieExpires }) + Cookies.set('rememberMe', user.rememberMe, { expires: Config.passCookieExpires }) + } else { + Cookies.remove('username') + Cookies.remove('password') + Cookies.remove('rememberMe') + } + this.$store.dispatch('Login', user).then(() => { + this.loading = false + this.$router.push({ path: this.redirect || '/' }) + }).catch(() => { + this.loading = false + this.getCode() + }) + } else { + console.log('error submit!!') + return false + } + }) + }, + point() { + const point = Cookies.get('point') !== undefined + if (point) { + this.$notify({ + title: '提示', + message: '当前登录状态已过期,请重新登录!', + type: 'warning', + duration: 5000 + }) + Cookies.remove('point') + } + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss"> + .login { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + background-size: cover; + } + .title { + margin: 0 auto 30px auto; + text-align: center; + color: #707070; + } + + .login-form { + border-radius: 6px; + background: #ffffff; + width: 385px; + padding: 25px 25px 5px 25px; + .el-input { + height: 38px; + input { + height: 38px; + } + } + .input-icon{ + height: 39px;width: 14px;margin-left: 2px; + } + } + .login-tip { + font-size: 13px; + text-align: center; + color: #bfbfbf; + } + .login-code { + width: 33%; + display: inline-block; + height: 38px; + float: right; + + img{ + cursor: pointer; + vertical-align:middle + } + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/mnt/app/index.vue b/UI source code/dns_mapping_ui-master/src/views/mnt/app/index.vue new file mode 100644 index 0000000..ddb8fb8 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/mnt/app/index.vue @@ -0,0 +1,144 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.name" clearable placeholder="输入名称搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <rrOperation /> + </div> + <crudOperation :permission="permission"> + <el-button + slot="left" + v-permission="['admin','app:add']" + :disabled="!currentRow" + class="filter-item" + size="mini" + type="primary" + icon="el-icon-plus" + @click="copy" + >复制</el-button> + </crudOperation> + </div> + <!--表单组件--> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="800px"> + <el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px"> + <el-form-item label="应用名称" prop="name"> + <el-input v-model="form.name" style="width: 670px" placeholder="部署后的文件或者目录名称,用于备份" /> + </el-form-item> + <el-form-item label="应用端口" prop="port"> + <el-input-number v-model.number="form.port" placeholder="例如:8080" /> + </el-form-item> + <el-form-item label="上传目录" prop="uploadPath"> + <el-input v-model="form.uploadPath" style="width: 670px" placeholder="例如: /opt/upload" /> + </el-form-item> + <el-form-item label="部署目录" prop="deployPath"> + <el-input v-model="form.deployPath" style="width: 670px" placeholder="例如: /opt/app" /> + </el-form-item> + <el-form-item label="备份目录" prop="backupPath"> + <el-input v-model="form.backupPath" style="width: 670px" placeholder="例如: /opt/backup" /> + </el-form-item> + <el-form-item label="部署脚本" prop="deployScript"> + <el-input v-model="form.deployScript" :rows="3" type="textarea" autosize style="width: 670px" placeholder="" /> + </el-form-item> + <el-form-item label="启动脚本" prop="startScript"> + <el-input v-model="form.startScript" :rows="3" type="textarea" autosize style="width: 670px" placeholder="" /> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row style="width: 100%" @selection-change="crud.selectionChangeHandler" @current-change="handleCurrentChange"> + <el-table-column type="selection" width="55" /> + <el-table-column prop="name" label="应用名称" /> + <el-table-column prop="port" label="端口号" /> + <el-table-column prop="uploadPath" label="上传目录" /> + <el-table-column prop="deployPath" label="部署目录" /> + <el-table-column prop="backupPath" label="备份目录" /> + <el-table-column prop="createTime" label="创建日期" /> + <el-table-column v-if="checkPer(['admin','app:edit','app:del'])" label="操作" width="150px" align="center"> + <template slot-scope="scope"> + <udOperation + :data="scope.row" + :permission="permission" + /> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> +import crudApp from '@/api/mnt/app' +import CRUD, { presenter, header, form, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import udOperation from '@crud/UD.operation' +import pagination from '@crud/Pagination' +import DateRangePicker from '@/components/DateRangePicker' + +const defaultForm = { id: null, name: null, port: 8080, uploadPath: '/opt/upload', deployPath: '/opt/app', backupPath: '/opt/backup', startScript: null, deployScript: null } +export default { + name: 'App', + components: { pagination, crudOperation, rrOperation, udOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '应用', url: 'api/app', crudMethod: { ...crudApp }}) + }, + mixins: [presenter(), header(), form(defaultForm), crud()], + data() { + return { + currentRow: null, + permission: { + add: ['admin', 'app:add'], + edit: ['admin', 'app:edit'], + del: ['admin', 'app:del'] + }, + rules: { + name: [ + { required: true, message: '请输入应用名称', trigger: 'blur' } + ], + port: [ + { required: true, message: '请输入应用端口', trigger: 'blur', type: 'number' } + ], + uploadPath: [ + { required: true, message: '请输入上传目录', trigger: 'blur' } + ], + deployPath: [ + { required: true, message: '请输入部署目录', trigger: 'blur' } + ], + backupPath: [ + { required: true, message: '请输入备份目录', trigger: 'blur' } + ], + startScript: [ + { required: true, message: '请输入启动脚本', trigger: 'blur' } + ], + deployScript: [ + { required: true, message: '请输入部署脚本', trigger: 'blur' } + ] + } + } + }, + methods: { + copy() { + for (const key in this.currentRow) { + this.form[key] = this.currentRow[key] + } + this.form.id = null + this.form.createTime = null + this.crud.toAdd() + }, + handleCurrentChange(row) { + this.currentRow = JSON.parse(JSON.stringify(row)) + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/mnt/database/execute.vue b/UI source code/dns_mapping_ui-master/src/views/mnt/database/execute.vue new file mode 100644 index 0000000..94622fc --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/mnt/database/execute.vue @@ -0,0 +1,86 @@ +<template> + <el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="执行脚本" width="400px"> + <el-form ref="form" :rules="rules" size="small"> + <el-upload + :action="databaseUploadApi" + :data="databaseInfo" + :headers="headers" + :on-success="handleSuccess" + :on-error="handleError" + class="upload-demo" + drag + > + <i class="el-icon-upload" /> + <div class="el-upload__text"> + 将文件拖到此处,或 + <em>点击上传</em> + </div> + <div slot="tip" class="el-upload__tip">上传后,系统会自动执行SQL脚本</div> + </el-upload> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="primary" @click="cancel">关闭</el-button> + </div> + </el-dialog> +</template> + +<script> +import { mapGetters } from 'vuex' +import { getToken } from '@/utils/auth' +export default { + props: { + databaseInfo: { + type: Object, + default() { + return {} + } + } + }, + data() { + return { + loading: false, + dialog: false, + headers: { + Authorization: getToken() + }, + rules: {} + } + }, + computed: { + ...mapGetters(['databaseUploadApi']) + }, + mounted() { + }, + methods: { + cancel() { + this.dialog = false + }, + handleSuccess(response, file, fileList) { + if (response === 'success') { + this.$notify({ + title: '执行成功', + type: 'success', + duration: 2500 + }) + } else { + this.$notify({ + title: response, + type: 'error', + duration: 0 + }) + } + }, + handleError(e, file, fileList) { + const msg = JSON.parse(e.message) + this.$notify({ + title: msg.message, + type: 'error', + duration: 0 + }) + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/mnt/database/index.vue b/UI source code/dns_mapping_ui-master/src/views/mnt/database/index.vue new file mode 100644 index 0000000..03d44a6 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/mnt/database/index.vue @@ -0,0 +1,148 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.blurry" clearable placeholder="模糊搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <rrOperation /> + </div> + <crudOperation :permission="permission"> + <el-button + slot="right" + v-permission="['admin','database:add']" + :disabled="!selectIndex" + class="filter-item" + size="mini" + type="warning" + icon="el-icon-upload" + @click="execute" + >执行脚本 + </el-button> + </crudOperation> + </div> + <!--表单组件--> + <eForm ref="execute" :database-info="currentRow" /> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="530px"> + <el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px"> + <el-form-item label="连接名称" prop="name"> + <el-input v-model="form.name" style="width: 370px" /> + </el-form-item> + <el-form-item label="JDBC地址" prop="jdbcUrl"> + <el-input v-model="form.jdbcUrl" style="width: 300px" /> + <el-button :loading="loading" type="success" @click="testConnectDatabase">测试</el-button> + </el-form-item> + <el-form-item label="用户" prop="userName"> + <el-input v-model="form.userName" style="width: 370px" /> + </el-form-item> + <el-form-item label="密码" prop="pwd"> + <el-input v-model="form.pwd" type="password" style="width: 370px" /> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row stripe style="width: 100%" @selection-change="handleCurrentChange"> + <el-table-column type="selection" width="55" /> + <el-table-column prop="name" width="130px" label="数据库名称" /> + <el-table-column prop="jdbcUrl" label="连接地址" /> + <el-table-column prop="userName" width="200px" label="用户名" /> + <el-table-column prop="createTime" width="200px" label="创建日期" /> + <el-table-column v-if="checkPer(['admin','database:edit','database:del'])" label="操作" width="150px" align="center"> + <template slot-scope="scope"> + <udOperation + :data="scope.row" + :permission="permission" + /> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> +import crudDatabase from '@/api/mnt/database' +import { testDbConnect } from '@/api/mnt/connect' +import eForm from './execute' +import CRUD, { presenter, header, form, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import udOperation from '@crud/UD.operation' +import pagination from '@crud/Pagination' +import DateRangePicker from '@/components/DateRangePicker' + +const defaultForm = { id: null, name: null, jdbcUrl: 'jdbc:mysql://', userName: null, pwd: null } +export default { + name: 'DataBase', + components: { eForm, pagination, crudOperation, rrOperation, udOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '数据库', url: 'api/database', crudMethod: { ...crudDatabase }}) + }, + mixins: [presenter(), header(), form(defaultForm), crud()], + data() { + return { + currentRow: {}, + selectIndex: '', + databaseInfo: '', + loading: false, + permission: { + add: ['admin', 'database:add'], + edit: ['admin', 'database:edit'], + del: ['admin', 'database:del'] + }, + rules: { + name: [ + { required: true, message: '请输入数据库名称', trigger: 'blur' } + ], + jdbcUrl: [ + { required: true, message: '请输入数据库连接地址', trigger: 'blur' } + ], + userName: [ + { required: true, message: '请输入用户名', trigger: 'blur' } + ], + pwd: [ + { required: true, message: '请输入数据库密码', trigger: 'blur' } + ] + } + } + }, + methods: { + testConnectDatabase() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.loading = true + testDbConnect(this.form).then((res) => { + this.loading = false + this.crud.notify(res ? '连接成功' : '连接失败', res ? 'success' : 'error') + }).catch(() => { + this.loading = false + }) + } + }) + }, + execute() { + this.$refs.execute.dialog = true + }, + handleCurrentChange(selection) { + this.crud.selections = selection + if (selection.length === 1) { + const row = selection[0] + this.selectIndex = row.id + this.currentRow = row + } else { + this.currentRow = {} + this.selectIndex = '' + } + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/mnt/deploy/deploy.vue b/UI source code/dns_mapping_ui-master/src/views/mnt/deploy/deploy.vue new file mode 100644 index 0000000..4a411b4 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/mnt/deploy/deploy.vue @@ -0,0 +1,190 @@ +<template> + <el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="应用部署" width="400px"> + <el-form ref="form" :model="form" :rules="rules" size="small"> + <el-upload + :action="deployUploadApi" + :data="deployInfo" + :headers="headers" + :on-success="handleSuccess" + :on-error="handleError" + class="upload-demo" + drag + > + <i class="el-icon-upload" /> + <div class="el-upload__text"> + 将文件拖到此处,或 + <em>点击上传</em> + </div> + <div slot="tip" class="el-upload__tip">多个应用上传文件名称为all.zip,数据库更新脚本扩展名为.sql,上传成功后系统自动部署系统。</div> + </el-upload> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="primary" @click="cancel">关闭</el-button> + </div> + </el-dialog> +</template> + +<script> +import { add, edit, getApps, getServers } from '@/api/mnt/deploy' +import { mapGetters } from 'vuex' +import { getToken } from '@/utils/auth' + +export default { + props: {}, + data() { + return { + loading: false, + dialog: false, + apps: [], + servers: [], + headers: { + Authorization: getToken() + }, + deployInfo: {}, + form: { + id: '', + appId: '', + ip: '', + selectIp: [] + }, + rules: {} + } + }, + computed: { + ...mapGetters(['deployUploadApi']) + }, + created() { + this.initWebSocket() + }, + mounted() { + this.initSelect() + }, + methods: { + cancel() { + this.resetForm() + }, + doSubmit() { + this.loading = true + if (this.isAdd) { + this.doAdd() + } else { + this.doEdit() + } + }, + joinIp() { + this.form.ip = '' + this.form.selectIp.forEach(ip => { + if (this.form.ip !== '') { + this.form.ip += ',' + } + this.form.ip += ip + }) + }, + doAdd() { + this.joinIp() + add(this.form) + .then(res => { + this.resetForm() + this.$notify({ + title: '添加成功', + type: 'success', + duration: 2500 + }) + this.loading = false + this.$parent.init() + }) + .catch(err => { + this.loading = false + console.log(err.response.data.message) + }) + }, + doEdit() { + this.joinIp() + edit(this.form) + .then(res => { + this.resetForm() + this.$notify({ + title: '修改成功', + type: 'success', + duration: 2500 + }) + this.loading = false + this.$parent.init() + }) + .catch(err => { + this.loading = false + console.log(err.response.data.message) + }) + }, + resetForm() { + this.dialog = false + this.$refs['form'].resetFields() + this.form = { + id: '', + appId: '', + ip: '', + selectIp: [] + } + }, + initSelect() { + getApps().then(res => { + this.apps = res.content + }) + getServers().then(res => { + this.servers = res.content + }) + }, + handleSuccess(response, file, fileList) { + this.cancel() + }, + // 监听上传失败 + handleError(e, file, fileList) { + const msg = JSON.parse(e.message) + this.$notify({ + title: msg.message, + type: 'error', + duration: 2500 + }) + }, + initWebSocket() { + const wsUri = process.env.VUE_APP_WS_API + '/webSocket/deploy' + this.websock = new WebSocket(wsUri) + this.websock.onerror = this.webSocketOnError + this.websock.onmessage = this.webSocketOnMessage + }, + webSocketOnError(e) { + this.$notify({ + title: 'WebSocket连接发生错误', + type: 'error', + duration: 0 + }) + }, + webSocketOnMessage(e) { + const data = JSON.parse(e.data) + if (data.msgType === 'INFO') { + this.$notify({ + title: '', + message: data.msg, + type: 'success', + dangerouslyUseHTMLString: true, + duration: 5500 + }) + } else if (data.msgType === 'ERROR') { + this.$notify({ + title: '', + message: data.msg, + dangerouslyUseHTMLString: true, + type: 'error', + duration: 0 + }) + } + }, + webSocketSend(agentData) { + this.websock.send(agentData) + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/mnt/deploy/index.vue b/UI source code/dns_mapping_ui-master/src/views/mnt/deploy/index.vue new file mode 100644 index 0000000..e2ab8a7 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/mnt/deploy/index.vue @@ -0,0 +1,229 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.appName" clearable placeholder="输入应用名称查询" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <rrOperation /> + </div> + <crudOperation :permission="permission"> + <template slot="right"> + <el-button + v-permission="['admin','deploy:add']" + :disabled="!selectIndex" + class="filter-item" + size="mini" + type="primary" + icon="el-icon-upload" + @click="sysRestore" + >系统还原 + </el-button> + <el-button + v-permission="['admin','deploy:add']" + :disabled="!selectIndex" + class="filter-item" + size="mini" + type="primary" + icon="el-icon-upload" + @click="serverStatus" + >状态查询 + </el-button> + <el-button + v-permission="['admin','deploy:add']" + :disabled="!selectIndex" + class="filter-item" + size="mini" + type="success" + icon="el-icon-upload" + @click="startServer" + >启动 + </el-button> + <el-button + v-permission="['admin','deploy:add']" + :disabled="!selectIndex" + class="filter-item" + size="mini" + type="danger" + icon="el-icon-upload" + @click="stopServer" + >停止 + </el-button> + <el-button + v-permission="['admin','deploy:add']" + :disabled="!selectIndex" + class="filter-item" + size="mini" + type="warning" + icon="el-icon-upload" + @click="deploy" + >一键部署 + </el-button> + </template> + </crudOperation> + </div> + <!--表单组件--> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="500px"> + <el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px"> + <el-form-item label="应用" prop="app.id"> + <el-select v-model.number="form.app.id" placeholder="请选择" style="width: 370px"> + <el-option v-for="item in apps" :key="item.id" :label="item.name" :value="item.id" /> + </el-select> + </el-form-item> + <el-form-item label="服务器" prop="deploys"> + <el-select v-model="form.deploys" multiple placeholder="请选择" style="width: 370px"> + <el-option v-for="item in servers" :key="item.id" :label="item.name" :value="item.id" /> + </el-select> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!--统还原组件--> + <fForm ref="sysRestore" :key="times" :app-name="appName" /> + <dForm ref="deploy" /> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row stripe style="width: 100%" @selection-change="handleCurrentChange"> + <el-table-column type="selection" width="55" /> + <el-table-column prop="app.name" label="应用名称" /> + <el-table-column prop="servers" label="服务器列表" /> + <el-table-column prop="createTime" label="部署日期" /> + <el-table-column v-if="checkPer(['admin','deploy:edit','deploy:del'])" label="操作" width="150px" align="center"> + <template slot-scope="scope"> + <udOperation + :data="scope.row" + :permission="permission" + /> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> +import crudDeploy from '@/api/mnt/deploy' +import dForm from './deploy' +import fForm from './sysRestore' +import CRUD, { presenter, header, form, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import udOperation from '@crud/UD.operation' +import pagination from '@crud/Pagination' +import DateRangePicker from '@/components/DateRangePicker' + +const defaultForm = { id: null, app: { id: null }, deploys: [] } +export default { + name: 'Deploy', + components: { dForm, fForm, pagination, crudOperation, rrOperation, udOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '部署', url: 'api/deploy', crudMethod: { ...crudDeploy }}) + }, + mixins: [presenter(), header(), form(defaultForm), crud()], + data() { + return { + currentRow: {}, selectIndex: '', appName: '', urlHistory: '', + times: 0, appId: '', deployId: '', apps: [], servers: [], + permission: { + add: ['admin', 'deploy:add'], + edit: ['admin', 'deploy:edit'], + del: ['admin', 'deploy:del'] + }, + rules: { + 'app.id': [ + { required: true, message: '应用不能为空', trigger: 'blur', type: 'number' } + ], + deploys: [ + { required: true, message: '服务器不能为空', trigger: 'blur' } + ] + } + } + }, + methods: { + [CRUD.HOOK.beforeRefresh]() { + this.selectIndex = '' + return true + }, + // 新增编辑前做的操作 + [CRUD.HOOK.beforeToCU](crud, form) { + this.initSelect() + const deploys = [] + form.deploys.forEach(function(deploy, index) { + deploys.push(deploy.id) + }) + this.form.deploys = deploys + }, + // 提交前 + [CRUD.HOOK.beforeSubmit]() { + const deploys = [] + this.form.deploys.forEach(function(data, index) { + const deploy = { id: data } + deploys.push(deploy) + }) + this.form.deploys = deploys + return true + }, + deploy() { + this.$refs.deploy.dialog = true + this.$refs.deploy.deployInfo = this.currentRow + }, + sysRestore() { + this.$refs.sysRestore.dialog = true + }, + handleCurrentChange(selection) { + this.crud.selections = selection + if (selection.length === 1) { + const row = selection[0] + this.selectIndex = row.id + this.currentRow = row + this.appName = row.app.name + this.times = this.times + 1 + this.appId = row.appId + this.deployId = row.id + } else { + this.currentRow = {} + this.selectIndex = '' + } + }, + startServer() { + crudDeploy.startServer(JSON.stringify(this.currentRow)) + .then(res => { + }) + .catch(err => { + console.log('error:' + err.response.data.message) + }) + }, + stopServer() { + crudDeploy.stopServer(JSON.stringify(this.currentRow)) + .then(res => { + }) + .catch(err => { + console.log('error:' + err.response.data.message) + }) + }, + serverStatus() { + crudDeploy.serverStatus(JSON.stringify(this.currentRow)) + .then(res => { + }) + .catch(err => { + console.log('error:' + err.response.data.message) + }) + }, + initSelect() { + crudDeploy.getApps().then(res => { + this.apps = res.content + }) + crudDeploy.getServers().then(res => { + this.servers = res.content + }) + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/mnt/deploy/sysRestore.vue b/UI source code/dns_mapping_ui-master/src/views/mnt/deploy/sysRestore.vue new file mode 100644 index 0000000..e44aed6 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/mnt/deploy/sysRestore.vue @@ -0,0 +1,108 @@ +<template> + <el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="系统还原" width="800px"> + <!--工具栏--> + <div class="head-container"> + <date-range-picker v-model="query.createTime" class="date-item" /> + <el-button class="filter-item" size="mini" type="success" icon="el-icon-search" @click="toQuery">搜索</el-button> + </div> + <el-form size="small" label-width="80px"> + <!--表格渲染--> + <el-table v-loading="loading" :data="data" style="width: 100%" @row-click="showRow"> + <el-table-column width="30px"> + <template slot-scope="scope"> + <el-radio v-model="radio" :label="scope.$index" /> + </template> + </el-table-column> + <el-table-column prop="appName" label="应用名称" /> + <el-table-column prop="ip" label="部署IP" /> + <el-table-column prop="deployDate" label="部署时间" /> + <el-table-column prop="deployUser" label="部署人员" /> + </el-table> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="cancel">取消</el-button> + <el-button v-permission="['admin','deploy:add']" :loading="submitLoading" type="primary" @click="doSubmit">确认</el-button> + </div> + <!--分页组件--> + <el-pagination + :total="total" + :current-page="page + 1" + style="margin-top: 8px" + layout="total, prev, pager, next, sizes" + @size-change="sizeChange" + @current-change="pageChange" + /> + </el-dialog> +</template> + +<script> +import crud from '@/mixins/crud' +import { reducte } from '@/api/mnt/deployHistory' +import DateRangePicker from '@/components/DateRangePicker' +export default { + components: { DateRangePicker }, + mixins: [crud], + props: { + appName: { + type: String, + default: '' + } + }, + data() { + return { + submitLoading: false, + dialog: false, + history: [], + radio: '', + appNames: '', + selectIndex: '' + } + }, + created() { + this.$nextTick(() => { + this.init() + }) + }, + methods: { + beforeInit() { + this.url = 'api/deployHistory' + this.deployId = this.$parent.deployId + if (this.deployId === '') { + return false + } + this.sort = 'deployDate,desc' + this.params['deployId'] = this.deployId + return true + }, + showRow(row) { + this.radio = this.data.indexOf(row) + this.selectIndex = row.id + }, + cancel() { + this.dialog = false + this.submitLoading = false + }, + doSubmit() { + if (this.selectIndex === '') { + this.$message.error('请选择要还原的备份') + } else { + this.submitLoading = true + reducte(JSON.stringify(this.data[this.radio])) + .then(res => { + this.dialog = false + this.submitLoading = false + this.appNames = '' + this.$parent.crud.toQuery() + }) + .catch(err => { + this.submitLoading = false + console.log('error:' + err.response.data.message) + }) + } + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/mnt/deployHistory/index.vue b/UI source code/dns_mapping_ui-master/src/views/mnt/deployHistory/index.vue new file mode 100644 index 0000000..c4f9728 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/mnt/deployHistory/index.vue @@ -0,0 +1,93 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.blurry" clearable placeholder="输入搜索内容" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <date-range-picker v-model="query.deployDate" class="date-item" /> + <rrOperation /> + </div> + <crudOperation :permission="permission" /> + </div> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%" @selection-change="crud.selectionChangeHandler"> + <el-table-column type="selection" width="55" /> + <el-table-column prop="appName" label="应用名称" /> + <el-table-column prop="ip" label="部署IP" /> + <el-table-column prop="deployUser" label="部署人员" /> + <el-table-column prop="deployDate" label="部署时间" /> + <el-table-column v-if="checkPer(['admin','deployHistory:del'])" label="操作" width="100px" align="center"> + <template slot-scope="scope"> + <el-popover + :ref="scope.row.id" + v-permission="['admin','deployHistory:del']" + placement="top" + width="180" + > + <p>确定删除本条数据吗?</p> + <div style="text-align: right; margin: 0"> + <el-button size="mini" type="text" @click="$refs[scope.row.id].doClose()">取消</el-button> + <el-button :loading="delLoading" type="primary" size="mini" @click="delMethod(scope.row.id)">确定</el-button> + </div> + <el-button slot="reference" type="danger" icon="el-icon-delete" size="mini" /> + </el-popover> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> +import { del } from '@/api/mnt/deployHistory' +import CRUD, { presenter, header } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import pagination from '@crud/Pagination' +import DateRangePicker from '@/components/DateRangePicker' + +export default { + name: 'DeployHistory', + components: { pagination, crudOperation, rrOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '部署历史', url: 'api/deployHistory', crudMethod: { del }}) + }, + mixins: [presenter(), header()], + data() { + return { + delLoading: false, + permission: { + del: ['admin', 'deployHistory:del'] + } + } + }, + created() { + this.crud.optShow = { + add: false, + edit: false, + del: true, + download: true + } + }, + methods: { + delMethod(id) { + this.delLoading = true + del([id]).then(() => { + this.delLoading = false + this.$refs[id].doClose() + this.crud.dleChangePage(1) + this.crud.delSuccessNotify() + this.crud.toQuery() + }).catch(() => { + this.delLoading = false + this.$refs[id].doClose() + }) + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/mnt/server/index.vue b/UI source code/dns_mapping_ui-master/src/views/mnt/server/index.vue new file mode 100644 index 0000000..c26cc9c --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/mnt/server/index.vue @@ -0,0 +1,136 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.id" clearable placeholder="输入名称或IP搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <rrOperation /> + </div> + <crudOperation :permission="permission" /> + </div> + <!--表单组件--> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="470px"> + <el-form ref="form" :model="form" :rules="rules" size="small" label-width="55px"> + <el-form-item label="名称" prop="name"> + <el-input v-model="form.name" style="width: 370px" /> + </el-form-item> + <el-form-item label="IP" prop="ip"> + <el-input v-model="form.ip" style="width: 370px" /> + </el-form-item> + <el-form-item label="端口" prop="port"> + <el-input-number v-model.number="form.port" controls-position="right" style="width: 370px;" /> + </el-form-item> + <el-form-item label="账号" prop="account"> + <el-input v-model="form.account" style="width: 370px" /> + </el-form-item> + <el-form-item label="密码" prop="password"> + <el-input v-model="form.password" type="password" style="width: 200px" /> + <el-button :loading="loading" type="success" style="align: right;" @click="testConnectServer">测试连接</el-button> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%" @selection-change="crud.selectionChangeHandler"> + <el-table-column type="selection" width="55" /> + <el-table-column prop="name" label="名称" /> + <el-table-column prop="ip" label="IP" /> + <el-table-column prop="port" label="端口" /> + <el-table-column prop="account" label="账号" /> + <el-table-column prop="createTime" label="创建日期" /> + <el-table-column v-if="checkPer(['admin','serverDeploy:edit','serverDeploy:del'])" label="操作" width="150px" align="center"> + <template slot-scope="scope"> + <udOperation + :data="scope.row" + :permission="permission" + /> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> + +import crudServer from '@/api/mnt/serverDeploy' +import { testServerConnect } from '@/api/mnt/connect' +import { validateIP } from '@/utils/validate' +import CRUD, { presenter, header, form, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import udOperation from '@crud/UD.operation' +import pagination from '@crud/Pagination' +import DateRangePicker from '@/components/DateRangePicker' + +const defaultForm = { id: null, name: null, ip: null, port: 22, account: 'root', password: null } +export default { + name: 'Server', + components: { pagination, crudOperation, rrOperation, udOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '服务器', url: 'api/serverDeploy', crudMethod: { ...crudServer }}) + }, + mixins: [presenter(), header(), form(defaultForm), crud()], + data() { + return { + accountList: [], + accountMap: {}, + loading: false, + permission: { + add: ['admin', 'serverDeploy:add'], + edit: ['admin', 'serverDeploy:edit'], + del: ['admin', 'serverDeploy:del'] + }, + rules: { + name: [ + { required: true, message: '请输入名称', trigger: 'blur' } + ], + ip: [ + { required: true, message: '请输入IP', trigger: 'blur' }, + { validator: validateIP, trigger: 'change' } + ], + port: [ + { required: true, message: '请输入端口', trigger: 'blur', type: 'number' } + ], + account: [ + { required: true, message: '请输入账号', trigger: 'blur' } + ], + password: [ + { required: true, message: '请输入密码', trigger: 'blur' } + ] + } + } + }, + methods: { + testConnectServer() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.loading = true + testServerConnect(this.form).then((res) => { + this.loading = false + this.$notify({ + title: res ? '连接成功' : '连接失败', + type: res ? 'success' : 'error', + duration: 2500 + }) + }).catch(() => { + this.loading = false + }) + } + }) + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> + ::v-deep .el-input-number .el-input__inner { + text-align: left; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/monitor/log/errorLog.vue b/UI source code/dns_mapping_ui-master/src/views/monitor/log/errorLog.vue new file mode 100644 index 0000000..9f2004e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/monitor/log/errorLog.vue @@ -0,0 +1,135 @@ +<template> + <div class="app-container"> + <div class="head-container"> + <Search /> + <crudOperation> + <el-button + slot="left" + class="filter-item" + type="danger" + icon="el-icon-delete" + size="mini" + :loading="crud.delAllLoading" + @click="confirmDelAll()" + > + 清空 + </el-button> + </crudOperation> + </div> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> + <el-table-column type="expand"> + <template slot-scope="props"> + <el-form label-position="left" inline class="demo-table-expand"> + <el-form-item label="请求方法"> + <span>{{ props.row.method }}</span> + </el-form-item> + <el-form-item label="请求参数"> + <span>{{ props.row.params }}</span> + </el-form-item> + </el-form> + </template> + </el-table-column> + <el-table-column prop="username" label="用户名" /> + <el-table-column prop="requestIp" label="IP" /> + <el-table-column :show-overflow-tooltip="true" prop="address" label="IP来源" /> + <el-table-column prop="description" label="描述" /> + <el-table-column prop="browser" label="浏览器" /> + <el-table-column prop="createTime" label="创建日期" /> + <el-table-column label="异常详情" width="100px"> + <template slot-scope="scope"> + <el-button size="mini" type="text" @click="info(scope.row.id)">查看详情</el-button> + </template> + </el-table-column> + </el-table> + <el-dialog :visible.sync="dialog" title="异常详情" append-to-body top="30px" width="85%"> + <pre v-highlightjs="errorInfo"><code class="java" /></pre> + </el-dialog> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> +import { getErrDetail, delAllError } from '@/api/monitor/log' +import Search from './search' +import CRUD, { presenter } from '@crud/crud' +import crudOperation from '@crud/CRUD.operation' +import pagination from '@crud/Pagination' + +export default { + name: 'ErrorLog', + components: { Search, crudOperation, pagination }, + cruds() { + return CRUD({ title: '异常日志', url: 'api/logs/error' }) + }, + mixins: [presenter()], + data() { + return { + errorInfo: '', dialog: false + } + }, + created() { + this.crud.optShow = { + add: false, + edit: false, + del: false, + download: true + } + }, + methods: { + // 获取异常详情 + info(id) { + this.dialog = true + getErrDetail(id).then(res => { + this.errorInfo = res.exception + }) + }, + confirmDelAll() { + this.$confirm(`确认清空所有异常日志吗?`, '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + this.crud.delAllLoading = true + delAllError().then(res => { + this.crud.delAllLoading = false + this.crud.dleChangePage(1) + this.crud.delSuccessNotify() + this.crud.toQuery() + }).catch(err => { + this.crud.delAllLoading = false + console.log(err.response.data.message) + }) + }).catch(() => { + }) + } + } +} +</script> + +<style scoped> +.demo-table-expand { + font-size: 0; +} +.demo-table-expand label { + width: 70px; + color: #99a9bf; +} +.demo-table-expand .el-form-item { + margin-right: 0; + margin-bottom: 0; + width: 100%; +} +.demo-table-expand .el-form-item__content { + font-size: 12px; +} +/deep/ .el-dialog__body { + padding: 0 20px 10px 20px !important; +} +.java.hljs { + color: #444; + background: #ffffff !important; + height: 630px !important; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/monitor/log/index.vue b/UI source code/dns_mapping_ui-master/src/views/monitor/log/index.vue new file mode 100644 index 0000000..41a00dc --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/monitor/log/index.vue @@ -0,0 +1,114 @@ +<template> + <div class="app-container"> + <div class="head-container"> + <Search /> + <crudOperation> + <el-button + slot="left" + class="filter-item" + type="danger" + icon="el-icon-delete" + size="mini" + :loading="crud.delAllLoading" + @click="confirmDelAll()" + > + 清空 + </el-button> + </crudOperation> + </div> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> + <el-table-column type="expand"> + <template slot-scope="props"> + <el-form label-position="left" inline class="demo-table-expand"> + <el-form-item label="请求方法"> + <span>{{ props.row.method }}</span> + </el-form-item> + <el-form-item label="请求参数"> + <span>{{ props.row.params }}</span> + </el-form-item> + </el-form> + </template> + </el-table-column> + <el-table-column prop="username" label="用户名" /> + <el-table-column prop="requestIp" label="IP" /> + <el-table-column :show-overflow-tooltip="true" prop="address" label="IP来源" /> + <el-table-column prop="description" label="描述" /> + <el-table-column prop="browser" label="浏览器" /> + <el-table-column prop="time" label="请求耗时" align="center"> + <template slot-scope="scope"> + <el-tag v-if="scope.row.time <= 300">{{ scope.row.time }}ms</el-tag> + <el-tag v-else-if="scope.row.time <= 1000" type="warning">{{ scope.row.time }}ms</el-tag> + <el-tag v-else type="danger">{{ scope.row.time }}ms</el-tag> + </template> + </el-table-column> + <el-table-column prop="createTime" label="创建日期" width="180px" /> + </el-table> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> +import Search from './search' +import { delAllInfo } from '@/api/monitor/log' +import CRUD, { presenter } from '@crud/crud' +import crudOperation from '@crud/CRUD.operation' +import pagination from '@crud/Pagination' + +export default { + name: 'Log', + components: { Search, crudOperation, pagination }, + cruds() { + return CRUD({ title: '日志', url: 'api/logs' }) + }, + mixins: [presenter()], + created() { + this.crud.optShow = { + add: false, + edit: false, + del: false, + download: true + } + }, + methods: { + confirmDelAll() { + this.$confirm(`确认清空所有操作日志吗?`, '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + this.crud.delAllLoading = true + delAllInfo().then(res => { + this.crud.delAllLoading = false + this.crud.dleChangePage(1) + this.crud.delSuccessNotify() + this.crud.toQuery() + }).catch(err => { + this.crud.delAllLoading = false + console.log(err.response.data.message) + }) + }).catch(() => { + }) + } + } +} +</script> + +<style> +.demo-table-expand { + font-size: 0; +} +.demo-table-expand label { + width: 70px; + color: #99a9bf; +} +.demo-table-expand .el-form-item { + margin-right: 0; + margin-bottom: 0; + width: 100%; +} +.demo-table-expand .el-form-item__content { + font-size: 12px; +} +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/monitor/log/search.vue b/UI source code/dns_mapping_ui-master/src/views/monitor/log/search.vue new file mode 100644 index 0000000..ffbcc06 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/monitor/log/search.vue @@ -0,0 +1,24 @@ +<template> + <div v-if="crud.props.searchToggle"> + <el-input + v-model="query.blurry" + clearable + size="small" + placeholder="请输入你要搜索的内容" + style="width: 200px;" + class="filter-item" + /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <rrOperation /> + </div> +</template> + +<script> +import { header } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import DateRangePicker from '@/components/DateRangePicker' +export default { + components: { rrOperation, DateRangePicker }, + mixins: [header()] +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/views/monitor/online/index.vue b/UI source code/dns_mapping_ui-master/src/views/monitor/online/index.vue new file mode 100644 index 0000000..b35224d --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/monitor/online/index.vue @@ -0,0 +1,121 @@ +<template> + <div class="app-container"> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <el-input v-model="query.filter" clearable size="small" placeholder="全表模糊搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <rrOperation /> + </div> + <crudOperation> + <el-button + slot="left" + class="filter-item" + type="danger" + icon="el-icon-delete" + size="mini" + :loading="delLoading" + :disabled="crud.selections.length === 0" + @click="doDelete(crud.selections)" + > + 强退 + </el-button> + </crudOperation> + </div> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> + <el-table-column type="selection" width="55" /> + <el-table-column prop="userName" label="用户名" /> + <el-table-column prop="nickName" label="用户昵称" /> + <el-table-column prop="dept" label="部门" /> + <el-table-column prop="ip" label="登录IP" /> + <el-table-column :show-overflow-tooltip="true" prop="address" label="登录地点" /> + <el-table-column prop="browser" label="浏览器" /> + <el-table-column prop="loginTime" label="登录时间" /> + <el-table-column label="操作" width="70px" fixed="right"> + <template slot-scope="scope"> + <el-popover + :ref="scope.$index" + v-permission="['admin']" + placement="top" + width="180" + > + <p>确定强制退出该用户吗?</p> + <div style="text-align: right; margin: 0"> + <el-button size="mini" type="text" @click="$refs[scope.$index].doClose()">取消</el-button> + <el-button :loading="delLoading" type="primary" size="mini" @click="delMethod(scope.row.key, scope.$index)">确定</el-button> + </div> + <el-button slot="reference" size="mini" type="text">强退</el-button> + </el-popover> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> +import { del } from '@/api/monitor/online' +import CRUD, { presenter, header, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import pagination from '@crud/Pagination' + +export default { + name: 'OnlineUser', + components: { pagination, crudOperation, rrOperation }, + cruds() { + return CRUD({ url: 'auth/online', title: '在线用户' }) + }, + mixins: [presenter(), header(), crud()], + data() { + return { + delLoading: false, + permission: {} + } + }, + created() { + this.crud.msg.del = '强退成功!' + this.crud.optShow = { + add: false, + edit: false, + del: false, + download: true + } + }, + methods: { + doDelete(datas) { + this.$confirm(`确认强退选中的${datas.length}个用户?`, '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + this.delMethod(datas) + }).catch(() => {}) + }, + // 踢出用户 + delMethod(key, index) { + const ids = [] + if (key instanceof Array) { + key.forEach(val => { + ids.push(val.key) + }) + } else ids.push(key) + this.delLoading = true + del(ids).then(() => { + this.delLoading = false + if (this.$refs[index]) { + this.$refs[index].doClose() + } + this.crud.dleChangePage(1) + this.crud.delSuccessNotify() + this.crud.toQuery() + }).catch(() => { + this.delLoading = false + if (this.$refs[index]) { + this.$refs[index].doClose() + } + }) + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/views/monitor/server/index.vue b/UI source code/dns_mapping_ui-master/src/views/monitor/server/index.vue new file mode 100644 index 0000000..920861e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/monitor/server/index.vue @@ -0,0 +1,291 @@ +<template> + <div v-loading="!show" element-loading-text="数据加载中..." :style="!show ? 'height: 500px' : 'height: 100%'" class="app-container"> + <div v-if="show"> + <el-card class="box-card"> + <div style="color: #666;font-size: 13px;"> + <svg-icon icon-class="system" style="margin-right: 5px" /> + <span> + 系统:{{ data.sys.os }} + </span> + <span> + IP:{{ data.sys.ip }} + </span> + <span> + 项目已不间断运行:{{ data.sys.day }} + </span> + <i class="el-icon-refresh" style="margin-left: 40px" @click="init" /> + </div> + </el-card> + <el-card class="box-card"> + <div slot="header" class="clearfix"> + <span style="font-weight: bold;color: #666;font-size: 15px">状态</span> + </div> + <div> + <el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px"> + <div class="title">CPU使用率</div> + <el-tooltip placement="top-end"> + <div slot="content" style="font-size: 12px;"> + <div style="padding: 3px;"> + {{ data.cpu.name }} + </div> + <div style="padding: 3px"> + {{ data.cpu.package }} + </div> + <div style="padding: 3px"> + {{ data.cpu.core }} + </div> + <div style="padding: 3px"> + {{ data.cpu.logic }} + </div> + </div> + <div class="content"> + <el-progress type="dashboard" :percentage="parseFloat(data.cpu.used)" /> + </div> + </el-tooltip> + <div class="footer">{{ data.cpu.coreNumber }} 核心</div> + </el-col> + <el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px"> + <div class="title">内存使用率</div> + <el-tooltip placement="top-end"> + <div slot="content" style="font-size: 12px;"> + <div style="padding: 3px;"> + 总量:{{ data.memory.total }} + </div> + <div style="padding: 3px"> + 已使用:{{ data.memory.used }} + </div> + <div style="padding: 3px"> + 空闲:{{ data.memory.available }} + </div> + </div> + <div class="content"> + <el-progress type="dashboard" :percentage="parseFloat(data.memory.usageRate)" /> + </div> + </el-tooltip> + <div class="footer">{{ data.memory.used }} / {{ data.memory.total }}</div> + </el-col> + <el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px"> + <div class="title">交换区使用率</div> + <el-tooltip placement="top-end"> + <div slot="content" style="font-size: 12px;"> + <div style="padding: 3px;"> + 总量:{{ data.swap.total }} + </div> + <div style="padding: 3px"> + 已使用:{{ data.swap.used }} + </div> + <div style="padding: 3px"> + 空闲:{{ data.swap.available }} + </div> + </div> + <div class="content"> + <el-progress type="dashboard" :percentage="parseFloat(data.swap.usageRate)" /> + </div> + </el-tooltip> + <div class="footer">{{ data.swap.used }} / {{ data.swap.total }}</div> + </el-col> + <el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px"> + <div class="title">磁盘使用率</div> + <div class="content"> + <el-tooltip placement="top-end"> + <div slot="content" style="font-size: 12px;"> + <div style="padding: 3px"> + 总量:{{ data.disk.total }} + </div> + <div style="padding: 3px"> + 空闲:{{ data.disk.available }} + </div> + </div> + <div class="content"> + <el-progress type="dashboard" :percentage="parseFloat(data.disk.usageRate)" /> + </div> + </el-tooltip> + </div> + <div class="footer">{{ data.disk.used }} / {{ data.disk.total }}</div> + </el-col> + </div> + </el-card> + + <div> + <el-row :gutter="6"> + <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" style="margin-bottom: 10px"> + <el-card class="box-card"> + <div slot="header" class="clearfix"> + <span style="font-weight: bold;color: #666;font-size: 15px">CPU使用率监控</span> + </div> + <div> + <v-chart :options="cpuInfo" /> + </div> + </el-card> + </el-col> + <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" style="margin-bottom: 10px"> + <el-card class="box-card"> + <div slot="header" class="clearfix"> + <span style="font-weight: bold;color: #666;font-size: 15px">内存使用率监控</span> + </div> + <div> + <v-chart :options="memoryInfo" /> + </div> + </el-card> + </el-col> + </el-row> + </div> + </div> + </div> +</template> + +<script> +import ECharts from 'vue-echarts' +import 'echarts/lib/chart/line' +import 'echarts/lib/component/polar' +import { initData } from '@/api/data' +export default { + name: 'ServerMonitor', + components: { + 'v-chart': ECharts + }, + data() { + return { + show: false, + monitor: null, + url: 'api/monitor', + data: {}, + cpuInfo: { + tooltip: { + trigger: 'axis' + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: [] + }, + yAxis: { + type: 'value', + min: 0, + max: 100, + interval: 20 + }, + series: [{ + data: [], + type: 'line', + areaStyle: { + normal: { + color: 'rgb(32, 160, 255)' // 改变区域颜色 + } + }, + itemStyle: { + normal: { + color: '#6fbae1', + lineStyle: { + color: '#6fbae1' // 改变折线颜色 + } + } + } + }] + }, + memoryInfo: { + tooltip: { + trigger: 'axis' + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: [] + }, + yAxis: { + type: 'value', + min: 0, + max: 100, + interval: 20 + }, + series: [{ + data: [], + type: 'line', + areaStyle: { + normal: { + color: 'rgb(32, 160, 255)' // 改变区域颜色 + } + }, + itemStyle: { + normal: { + color: '#6fbae1', + lineStyle: { + color: '#6fbae1' // 改变折线颜色 + } + } + } + }] + } + } + }, + created() { + this.init() + this.monitor = window.setInterval(() => { + setTimeout(() => { + this.init() + }, 2) + }, 3500) + }, + destroyed() { + clearInterval(this.monitor) + }, + methods: { + init() { + initData(this.url, {}).then(data => { + this.data = data + this.show = true + if (this.cpuInfo.xAxis.data.length >= 8) { + this.cpuInfo.xAxis.data.shift() + this.memoryInfo.xAxis.data.shift() + this.cpuInfo.series[0].data.shift() + this.memoryInfo.series[0].data.shift() + } + this.cpuInfo.xAxis.data.push(data.time) + this.memoryInfo.xAxis.data.push(data.time) + this.cpuInfo.series[0].data.push(parseFloat(data.cpu.used)) + this.memoryInfo.series[0].data.push(parseFloat(data.memory.usageRate)) + }) + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> + ::v-deep .box-card { + margin-bottom: 5px; + span { + margin-right: 28px; + } + .el-icon-refresh { + margin-right: 10px; + float: right; + cursor:pointer; + } + } + .cpu, .memory, .swap, .disk { + width: 20%; + float: left; + padding-bottom: 20px; + margin-right: 5%; + } + .title { + text-align: center; + font-size: 15px; + font-weight: 500; + color: #999; + margin-bottom: 16px; + } + .footer { + text-align: center; + font-size: 15px; + font-weight: 500; + color: #999; + margin-top: -5px; + margin-bottom: 10px; + } + .content { + text-align: center; + margin-top: 5px; + margin-bottom: 5px; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/monitor/sql/index.vue b/UI source code/dns_mapping_ui-master/src/views/monitor/sql/index.vue new file mode 100644 index 0000000..0ed9034 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/monitor/sql/index.vue @@ -0,0 +1,16 @@ +<template> + <elFrame :src="sqlApi" /> +</template> +<script> +import { mapGetters } from 'vuex' +import elFrame from '@/components/Iframe/index' +export default { + name: 'Sql', + components: { elFrame }, + computed: { + ...mapGetters([ + 'sqlApi' + ]) + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/views/nested/menu1/menu1-1/index.vue b/UI source code/dns_mapping_ui-master/src/views/nested/menu1/menu1-1/index.vue new file mode 100644 index 0000000..132fc3f --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/nested/menu1/menu1-1/index.vue @@ -0,0 +1,36 @@ +<template> + <div class="app-container"> + <el-alert :closable="false" title="三级菜单1" type="success" /> + <el-form label-width="170px" style="margin-top: 20px"> + <el-form-item label="三级菜单缓存功能测试区"> + <el-input v-model="input" placeholder="请输入内容" style="width: 360px;" /> + </el-form-item> + </el-form> + <div> + <blockquote class="my-blockquote"> 三级菜单缓存配置教程</blockquote> + <pre class="my-code"> + 1、将前后端代码更新为最新版版本,或对照提交记录修改,点击查看-> <a href="https://gitee.com/elunez/eladmin/commit/43d1a63577f9d5347924355708429a2d210e29f7" target="_blank">提交(1)</a>、<a href="https://gitee.com/elunez/eladmin/commit/46393875148fcca5eaa327d4073f72edb3752f5c" target="_blank">提交(2)</a>、<a href="https://gitee.com/elunez/eladmin-web/commit/c93c99d8921abbb2c52afc806635f5ca08d6bda8" target="_blank">提交(3)</a> + 2、将 二级菜单 的 菜单类型 设置为 目录 级别,并且原有的 组件路径 需要清空 + 3、将 三级菜单 的 菜单缓存 设置为 是,最后将 组件名称 填写正确 + 4、具体设置可参考 菜单管理 的 多级菜单 配置进行进行相应的修改 + </pre> + <blockquote class="my-blockquote">更多帮助</blockquote> + <pre class="my-code">QQ交流群:一群:891137268、二群:947578238、三群:659622532</pre> + </div> + </div> +</template> +<script> +export default { + name: 'Test', + data() { + return { + input: '' + } + } +} +</script> +<style scoped> + .my-code a{ + color:#009688; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/nested/menu1/menu1-2/index.vue b/UI source code/dns_mapping_ui-master/src/views/nested/menu1/menu1-2/index.vue new file mode 100644 index 0000000..8508f4a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/nested/menu1/menu1-2/index.vue @@ -0,0 +1,5 @@ +<template> + <div style="padding:30px;"> + <el-alert :closable="false" title="三级菜单2" type="success" /> + </div> +</template> diff --git a/UI source code/dns_mapping_ui-master/src/views/nested/menu2/index.vue b/UI source code/dns_mapping_ui-master/src/views/nested/menu2/index.vue new file mode 100644 index 0000000..b8283a2 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/nested/menu2/index.vue @@ -0,0 +1,5 @@ +<template> + <div style="padding:30px;"> + <el-alert :closable="false" title="二级菜单" /> + </div> +</template> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/dept/index.vue b/UI source code/dns_mapping_ui-master/src/views/system/dept/index.vue new file mode 100644 index 0000000..d02b846 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/dept/index.vue @@ -0,0 +1,254 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.name" clearable size="small" placeholder="输入部门名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <el-select v-model="query.enabled" clearable size="small" placeholder="状态" class="filter-item" style="width: 90px" @change="crud.toQuery"> + <el-option v-for="item in enabledTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" /> + </el-select> + <rrOperation /> + </div> + <crudOperation :permission="permission" /> + </div> + <!--表单组件--> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="500px"> + <el-form ref="form" inline :model="form" :rules="rules" size="small" label-width="80px"> + <el-form-item label="部门名称" prop="name"> + <el-input v-model="form.name" style="width: 370px;" /> + </el-form-item> + <el-form-item label="部门排序" prop="deptSort"> + <el-input-number + v-model.number="form.deptSort" + :min="0" + :max="999" + controls-position="right" + style="width: 370px;" + /> + </el-form-item> + <el-form-item label="顶级部门"> + <el-radio-group v-model="form.isTop" style="width: 140px"> + <el-radio label="1">是</el-radio> + <el-radio label="0">否</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="状态" prop="enabled"> + <el-radio v-for="item in dict.dept_status" :key="item.id" v-model="form.enabled" :label="item.value">{{ item.label }}</el-radio> + </el-form-item> + <el-form-item v-if="form.isTop === '0'" style="margin-bottom: 0;" label="上级部门" prop="pid"> + <treeselect + v-model="form.pid" + :load-options="loadDepts" + :options="depts" + style="width: 370px;" + placeholder="选择上级类目" + /> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!--表格渲染--> + <el-table + ref="table" + v-loading="crud.loading" + lazy + :load="getDeptDatas" + :tree-props="{children: 'children', hasChildren: 'hasChildren'}" + :data="crud.data" + row-key="id" + @select="crud.selectChange" + @select-all="crud.selectAllChange" + @selection-change="crud.selectionChangeHandler" + > + <el-table-column :selectable="checkboxT" type="selection" width="55" /> + <el-table-column label="名称" prop="name" /> + <el-table-column label="排序" prop="deptSort" /> + <el-table-column label="状态" align="center" prop="enabled"> + <template slot-scope="scope"> + <el-switch + v-model="scope.row.enabled" + :disabled="scope.row.id === 1" + active-color="#409EFF" + inactive-color="#F56C6C" + @change="changeEnabled(scope.row, scope.row.enabled,)" + /> + </template> + </el-table-column> + <el-table-column prop="createTime" label="创建日期" /> + <el-table-column v-if="checkPer(['admin','dept:edit','dept:del'])" label="操作" width="130px" align="center" fixed="right"> + <template slot-scope="scope"> + <udOperation + :data="scope.row" + :permission="permission" + :disabled-dle="scope.row.id === 1" + msg="确定删除吗,如果存在下级节点则一并删除,此操作不能撤销!" + /> + </template> + </el-table-column> + </el-table> + </div> +</template> + +<script> +import crudDept from '@/api/system/dept' +import Treeselect from '@riophae/vue-treeselect' +import '@riophae/vue-treeselect/dist/vue-treeselect.css' +import { LOAD_CHILDREN_OPTIONS } from '@riophae/vue-treeselect' +import CRUD, { presenter, header, form, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import udOperation from '@crud/UD.operation' +import DateRangePicker from '@/components/DateRangePicker' + +const defaultForm = { id: null, name: null, isTop: '1', subCount: 0, pid: null, deptSort: 999, enabled: 'true' } +export default { + name: 'Dept', + components: { Treeselect, crudOperation, rrOperation, udOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '部门', url: 'api/dept', crudMethod: { ...crudDept }}) + }, + mixins: [presenter(), header(), form(defaultForm), crud()], + // 设置数据字典 + dicts: ['dept_status'], + data() { + return { + depts: [], + rules: { + name: [ + { required: true, message: '请输入名称', trigger: 'blur' } + ], + deptSort: [ + { required: true, message: '请输入序号', trigger: 'blur', type: 'number' } + ] + }, + permission: { + add: ['admin', 'dept:add'], + edit: ['admin', 'dept:edit'], + del: ['admin', 'dept:del'] + }, + enabledTypeOptions: [ + { key: 'true', display_name: '正常' }, + { key: 'false', display_name: '禁用' } + ] + } + }, + methods: { + getDeptDatas(tree, treeNode, resolve) { + const params = { pid: tree.id } + setTimeout(() => { + crudDept.getDepts(params).then(res => { + resolve(res.content) + }) + }, 100) + }, + // 新增与编辑前做的操作 + [CRUD.HOOK.afterToCU](crud, form) { + if (form.pid !== null) { + form.isTop = '0' + } else if (form.id !== null) { + form.isTop = '1' + } + form.enabled = `${form.enabled}` + if (form.id != null) { + this.getSupDepts(form.id) + } else { + this.getDepts() + } + }, + getSupDepts(id) { + crudDept.getDeptSuperior(id).then(res => { + const date = res.content + this.buildDepts(date) + this.depts = date + }) + }, + buildDepts(depts) { + depts.forEach(data => { + if (data.children) { + this.buildDepts(data.children) + } + if (data.hasChildren && !data.children) { + data.children = null + } + }) + }, + getDepts() { + crudDept.getDepts({ enabled: true }).then(res => { + this.depts = res.content.map(function(obj) { + if (obj.hasChildren) { + obj.children = null + } + return obj + }) + }) + }, + // 获取弹窗内部门数据 + loadDepts({ action, parentNode, callback }) { + if (action === LOAD_CHILDREN_OPTIONS) { + crudDept.getDepts({ enabled: true, pid: parentNode.id }).then(res => { + parentNode.children = res.content.map(function(obj) { + if (obj.hasChildren) { + obj.children = null + } + return obj + }) + setTimeout(() => { + callback() + }, 100) + }) + } + }, + // 提交前的验证 + [CRUD.HOOK.afterValidateCU]() { + if (this.form.pid !== null && this.form.pid === this.form.id) { + this.$message({ + message: '上级部门不能为空', + type: 'warning' + }) + return false + } + if (this.form.isTop === '1') { + this.form.pid = null + } + return true + }, + // 改变状态 + changeEnabled(data, val) { + this.$confirm('此操作将 "' + this.dict.label.dept_status[val] + '" ' + data.name + '部门, 是否继续?', '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + crudDept.edit(data).then(res => { + this.crud.notify(this.dict.label.dept_status[val] + '成功', CRUD.NOTIFICATION_TYPE.SUCCESS) + }).catch(err => { + data.enabled = !data.enabled + console.log(err.response.data.message) + }) + }).catch(() => { + data.enabled = !data.enabled + }) + }, + checkboxT(row, rowIndex) { + return row.id !== 1 + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> + ::v-deep .vue-treeselect__control,::v-deep .vue-treeselect__placeholder,::v-deep .vue-treeselect__single-value { + height: 30px; + line-height: 30px; + } +</style> +<style rel="stylesheet/scss" lang="scss" scoped> + ::v-deep .el-input-number .el-input__inner { + text-align: left; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/dict/dictDetail.vue b/UI source code/dns_mapping_ui-master/src/views/system/dict/dictDetail.vue new file mode 100644 index 0000000..32756da --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/dict/dictDetail.vue @@ -0,0 +1,115 @@ +<template> + <div> + <div v-if="query.dictName === ''"> + <div class="my-code">点击字典查看详情</div> + </div> + <div v-else> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.label" clearable size="small" placeholder="输入字典标签查询" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" /> + <rrOperation /> + </div> + </div> + <!--表单组件--> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible="crud.status.cu > 0" :title="crud.status.title" width="500px"> + <el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px"> + <el-form-item label="字典标签" prop="label"> + <el-input v-model="form.label" style="width: 370px;" /> + </el-form-item> + <el-form-item label="字典值" prop="value"> + <el-input v-model="form.value" style="width: 370px;" /> + </el-form-item> + <el-form-item label="排序" prop="dictSort"> + <el-input-number v-model.number="form.dictSort" :min="0" :max="999" controls-position="right" style="width: 370px;" /> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row style="width: 100%;" @selection-change="crud.selectionChangeHandler"> + <el-table-column label="所属字典"> + {{ query.dictName }} + </el-table-column> + <el-table-column prop="label" label="字典标签" /> + <el-table-column prop="value" label="字典值" /> + <el-table-column prop="dictSort" label="排序" /> + <el-table-column v-if="checkPer(['admin','dict:edit','dict:del'])" label="操作" width="130px" align="center" fixed="right"> + <template slot-scope="scope"> + <udOperation + :data="scope.row" + :permission="permission" + /> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </div> + </div> +</template> + +<script> +import crudDictDetail from '@/api/system/dictDetail' +import CRUD, { presenter, header, form } from '@crud/crud' +import pagination from '@crud/Pagination' +import rrOperation from '@crud/RR.operation' +import udOperation from '@crud/UD.operation' + +const defaultForm = { id: null, label: null, value: null, dictSort: 999 } + +export default { + components: { pagination, rrOperation, udOperation }, + cruds() { + return [ + CRUD({ title: '字典详情', url: 'api/dictDetail', query: { dictName: '' }, sort: ['dictSort,asc', 'id,desc'], + crudMethod: { ...crudDictDetail }, + optShow: { + add: true, + edit: true, + del: true, + reset: false + }, + queryOnPresenterCreated: false + }) + ] + }, + mixins: [ + presenter(), + header(), + form(function() { + return Object.assign({ dict: { id: this.dictId }}, defaultForm) + })], + data() { + return { + dictId: null, + rules: { + label: [ + { required: true, message: '请输入字典标签', trigger: 'blur' } + ], + value: [ + { required: true, message: '请输入字典值', trigger: 'blur' } + ], + dictSort: [ + { required: true, message: '请输入序号', trigger: 'blur', type: 'number' } + ] + }, + permission: { + add: ['admin', 'dict:add'], + edit: ['admin', 'dict:edit'], + del: ['admin', 'dict:del'] + } + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> + ::v-deep .el-input-number .el-input__inner { + text-align: left; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/dict/index.vue b/UI source code/dns_mapping_ui-master/src/views/system/dict/index.vue new file mode 100644 index 0000000..f102023 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/dict/index.vue @@ -0,0 +1,135 @@ +<template> + <div class="app-container"> + <!--表单组件--> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible="crud.status.cu > 0" :title="crud.status.title" width="500px"> + <el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px"> + <el-form-item label="字典名称" prop="name"> + <el-input v-model="form.name" style="width: 370px;" /> + </el-form-item> + <el-form-item label="描述"> + <el-input v-model="form.description" style="width: 370px;" /> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!-- 字典列表 --> + <el-row :gutter="10"> + <el-col :xs="24" :sm="24" :md="10" :lg="11" :xl="11" style="margin-bottom: 10px"> + <el-card class="box-card"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.blurry" clearable size="small" placeholder="输入名称或者描述搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <rrOperation /> + </div> + <crudOperation :permission="permission" /> + </div> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row style="width: 100%;" @selection-change="crud.selectionChangeHandler" @current-change="handleCurrentChange"> + <el-table-column type="selection" width="55" /> + <el-table-column :show-overflow-tooltip="true" prop="name" label="名称" /> + <el-table-column :show-overflow-tooltip="true" prop="description" label="描述" /> + <el-table-column v-if="checkPer(['admin','dict:edit','dict:del'])" label="操作" width="130px" align="center" fixed="right"> + <template slot-scope="scope"> + <udOperation + :data="scope.row" + :permission="permission" + /> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </el-card> + </el-col> + <!-- 字典详情列表 --> + <el-col :xs="24" :sm="24" :md="14" :lg="13" :xl="13"> + <el-card class="box-card"> + <div slot="header" class="clearfix"> + <span>字典详情</span> + <el-button + v-if="checkPer(['admin','dict:add']) && this.$refs.dictDetail && this.$refs.dictDetail.query.dictName" + class="filter-item" + size="mini" + style="float: right;padding: 4px 10px" + type="primary" + icon="el-icon-plus" + @click="$refs.dictDetail && $refs.dictDetail.crud.toAdd()" + >新增</el-button> + </div> + <dictDetail ref="dictDetail" :permission="permission" /> + </el-card> + </el-col> + </el-row> + </div> +</template> + +<script> +import dictDetail from './dictDetail' +import crudDict from '@/api/system/dict' +import CRUD, { presenter, header, form } from '@crud/crud' +import crudOperation from '@crud/CRUD.operation' +import pagination from '@crud/Pagination' +import rrOperation from '@crud/RR.operation' +import udOperation from '@crud/UD.operation' + +const defaultForm = { id: null, name: null, description: null, dictDetails: [] } + +export default { + name: 'Dict', + components: { crudOperation, pagination, rrOperation, udOperation, dictDetail }, + cruds() { + return [ + CRUD({ title: '字典', url: 'api/dict', crudMethod: { ...crudDict }}) + ] + }, + mixins: [presenter(), header(), form(defaultForm)], + data() { + return { + queryTypeOptions: [ + { key: 'name', display_name: '字典名称' }, + { key: 'description', display_name: '描述' } + ], + rules: { + name: [ + { required: true, message: '请输入名称', trigger: 'blur' } + ] + }, + permission: { + add: ['admin', 'dict:add'], + edit: ['admin', 'dict:edit'], + del: ['admin', 'dict:del'] + } + } + }, + methods: { + // 获取数据前设置好接口地址 + [CRUD.HOOK.beforeRefresh]() { + if (this.$refs.dictDetail) { + this.$refs.dictDetail.query.dictName = '' + } + return true + }, + // 选中字典后,设置字典详情数据 + handleCurrentChange(val) { + if (val) { + this.$refs.dictDetail.query.dictName = val.name + this.$refs.dictDetail.dictId = val.id + this.$refs.dictDetail.crud.toQuery() + } + }, + // 编辑前将字典明细临时清空,避免日志入库数据过长 + [CRUD.HOOK.beforeToEdit](crud, form) { + // 将角色的菜单清空,避免日志入库数据过长 + form.dictDetails = null + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/job/index.vue b/UI source code/dns_mapping_ui-master/src/views/system/job/index.vue new file mode 100644 index 0000000..e17ea75 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/job/index.vue @@ -0,0 +1,110 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <eHeader :dict="dict" :permission="permission" /> + <crudOperation :permission="permission" /> + </div> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> + <el-table-column type="selection" width="55" /> + <el-table-column prop="name" label="名称" /> + <el-table-column prop="jobSort" label="排序"> + <template slot-scope="scope"> + {{ scope.row.jobSort }} + </template> + </el-table-column> + <el-table-column prop="status" label="状态" align="center"> + <template slot-scope="scope"> + <el-switch + v-model="scope.row.enabled" + active-color="#409EFF" + inactive-color="#F56C6C" + @change="changeEnabled(scope.row, scope.row.enabled)" + /> + </template> + </el-table-column> + <el-table-column prop="createTime" label="创建日期" /> + <!-- 编辑与删除 --> + <el-table-column + v-if="checkPer(['admin','job:edit','job:del'])" + label="操作" + width="130px" + align="center" + fixed="right" + > + <template slot-scope="scope"> + <udOperation + :data="scope.row" + :permission="permission" + /> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + <!--表单渲染--> + <eForm :job-status="dict.job_status" /> + </div> +</template> + +<script> +import crudJob from '@/api/system/job' +import eHeader from './module/header' +import eForm from './module/form' +import CRUD, { presenter } from '@crud/crud' +import crudOperation from '@crud/CRUD.operation' +import pagination from '@crud/Pagination' +import udOperation from '@crud/UD.operation' +export default { + name: 'Job', + components: { eHeader, eForm, crudOperation, pagination, udOperation }, + cruds() { + return CRUD({ + title: '岗位', + url: 'api/job', + sort: ['jobSort,asc', 'id,desc'], + crudMethod: { ...crudJob } + }) + }, + mixins: [presenter()], + // 数据字典 + dicts: ['job_status'], + data() { + return { + permission: { + add: ['admin', 'job:add'], + edit: ['admin', 'job:edit'], + del: ['admin', 'job:del'] + } + } + }, + methods: { + // 改变状态 + changeEnabled(data, val) { + this.$confirm('此操作将 "' + this.dict.label.job_status[val] + '" ' + data.name + '岗位, 是否继续?', '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + // eslint-disable-next-line no-undef + crudJob.edit(data).then(() => { + // eslint-disable-next-line no-undef + this.crud.notify(this.dict.label.job_status[val] + '成功', 'success') + }).catch(err => { + data.enabled = !data.enabled + console.log(err.data.message) + }) + }).catch(() => { + data.enabled = !data.enabled + }) + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> + ::v-deep .el-input-number .el-input__inner { + text-align: left; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/job/module/form.vue b/UI source code/dns_mapping_ui-master/src/views/system/job/module/form.vue new file mode 100644 index 0000000..aa538fb --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/job/module/form.vue @@ -0,0 +1,110 @@ +<template> + <el-dialog + append-to-body + :close-on-click-modal="false" + :before-close="crud.cancelCU" + :visible="crud.status.cu > 0" + :title="crud.status.title" + width="500px" + > + <el-form + ref="form" + :model="form" + :rules="rules" + size="small" + label-width="80px" + > + <el-form-item + label="名称" + prop="name" + > + <el-input + v-model="form.name" + style="width: 370px;" + /> + </el-form-item> + <el-form-item + label="排序" + prop="jobSort" + > + <el-input-number + v-model.number="form.jobSort" + :min="0" + :max="999" + controls-position="right" + style="width: 370px;" + /> + </el-form-item> + <el-form-item + v-if="form.pid !== 0" + label="状态" + prop="enabled" + > + <el-radio + v-for="item in jobStatus" + :key="item.id" + v-model="form.enabled" + :label="item.value === 'true'" + > + {{ item.label }} + </el-radio> + </el-form-item> + </el-form> + <div + slot="footer" + class="dialog-footer" + > + <el-button + type="text" + @click="crud.cancelCU" + > + 取消 + </el-button> + <el-button + :loading="crud.status.cu === 2" + type="primary" + @click="crud.submitCU" + > + 确认 + </el-button> + </div> + </el-dialog> +</template> + +<script> +import { form } from '@crud/crud' + +const defaultForm = { + id: null, + name: '', + jobSort: 999, + enabled: true +} +export default { + mixins: [form(defaultForm)], + props: { + jobStatus: { + type: Array, + required: true + } + }, + data() { + return { + rules: { + name: [ + { required: true, message: '请输入名称', trigger: 'blur' } + ], + jobSort: [ + { required: true, message: '请输入序号', trigger: 'blur', type: 'number' } + ] + } + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> + ::v-deep .el-input-number .el-input__inner { + text-align: left; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/job/module/header.vue b/UI source code/dns_mapping_ui-master/src/views/system/job/module/header.vue new file mode 100644 index 0000000..6503317 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/job/module/header.vue @@ -0,0 +1,32 @@ +<template> + <div + v-if="crud.props.searchToggle" + > + <el-input v-model="query.name" clearable size="small" placeholder="输入岗位名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <el-select v-model="query.enabled" clearable size="small" placeholder="状态" class="filter-item" style="width: 90px" @change="crud.toQuery"> + <el-option v-for="item in dict.dict.job_status" :key="item.value" :label="item.label" :value="item.value" /> + </el-select> + <rrOperation /> + </div> +</template> + +<script> +import { header } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import DateRangePicker from '@/components/DateRangePicker' +export default { + components: { rrOperation, DateRangePicker }, + mixins: [header()], + props: { + dict: { + type: Object, + required: true + }, + permission: { + type: Object, + required: true + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/menu/index.vue b/UI source code/dns_mapping_ui-master/src/views/system/menu/index.vue new file mode 100644 index 0000000..e4800e1 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/menu/index.vue @@ -0,0 +1,252 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.blurry" clearable size="small" placeholder="模糊搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <rrOperation /> + </div> + <crudOperation :permission="permission" /> + </div> + <!--表单渲染--> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="580px"> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="80px"> + <el-form-item label="菜单类型" prop="type"> + <el-radio-group v-model="form.type" size="mini" style="width: 178px"> + <el-radio-button label="0">目录</el-radio-button> + <el-radio-button label="1">菜单</el-radio-button> + <el-radio-button label="2">按钮</el-radio-button> + </el-radio-group> + </el-form-item> + <el-form-item v-show="form.type.toString() !== '2'" label="菜单图标" prop="icon"> + <el-popover + placement="bottom-start" + width="450" + trigger="click" + @show="$refs['iconSelect'].reset()" + > + <IconSelect ref="iconSelect" @selected="selected" /> + <el-input slot="reference" v-model="form.icon" style="width: 450px;" placeholder="点击选择图标" readonly> + <svg-icon v-if="form.icon" slot="prefix" :icon-class="form.icon" class="el-input__icon" style="height: 32px;width: 16px;" /> + <i v-else slot="prefix" class="el-icon-search el-input__icon" /> + </el-input> + </el-popover> + </el-form-item> + <el-form-item v-show="form.type.toString() !== '2'" label="外链菜单" prop="iFrame"> + <el-radio-group v-model="form.iFrame" size="mini"> + <el-radio-button label="true">是</el-radio-button> + <el-radio-button label="false">否</el-radio-button> + </el-radio-group> + </el-form-item> + <el-form-item v-show="form.type.toString() === '1'" label="菜单缓存" prop="cache"> + <el-radio-group v-model="form.cache" size="mini"> + <el-radio-button label="true">是</el-radio-button> + <el-radio-button label="false">否</el-radio-button> + </el-radio-group> + </el-form-item> + <el-form-item v-show="form.type.toString() !== '2'" label="菜单可见" prop="hidden"> + <el-radio-group v-model="form.hidden" size="mini"> + <el-radio-button label="false">是</el-radio-button> + <el-radio-button label="true">否</el-radio-button> + </el-radio-group> + </el-form-item> + <el-form-item v-if="form.type.toString() !== '2'" label="菜单标题" prop="title"> + <el-input v-model="form.title" :style=" form.type.toString() === '0' ? 'width: 450px' : 'width: 178px'" placeholder="菜单标题" /> + </el-form-item> + <el-form-item v-if="form.type.toString() === '2'" label="按钮名称" prop="title"> + <el-input v-model="form.title" placeholder="按钮名称" style="width: 178px;" /> + </el-form-item> + <el-form-item v-show="form.type.toString() !== '0'" label="权限标识" prop="permission"> + <el-input v-model="form.permission" :disabled="form.iFrame.toString() === 'true'" placeholder="权限标识" style="width: 178px;" /> + </el-form-item> + <el-form-item v-if="form.type.toString() !== '2'" label="路由地址" prop="path"> + <el-input v-model="form.path" placeholder="路由地址" style="width: 178px;" /> + </el-form-item> + <el-form-item label="菜单排序" prop="menuSort"> + <el-input-number v-model.number="form.menuSort" :min="0" :max="999" controls-position="right" style="width: 178px;" /> + </el-form-item> + <el-form-item v-show="form.iFrame.toString() !== 'true' && form.type.toString() === '1'" label="组件名称" prop="componentName"> + <el-input v-model="form.componentName" style="width: 178px;" placeholder="匹配组件内Name字段" /> + </el-form-item> + <el-form-item v-show="form.iFrame.toString() !== 'true' && form.type.toString() === '1'" label="组件路径" prop="component"> + <el-input v-model="form.component" style="width: 178px;" placeholder="组件路径" /> + </el-form-item> + <el-form-item label="上级类目" prop="pid"> + <treeselect + v-model="form.pid" + :options="menus" + :load-options="loadMenus" + style="width: 450px;" + placeholder="选择上级类目" + /> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!--表格渲染--> + <el-table + ref="table" + v-loading="crud.loading" + lazy + :load="getMenus" + :data="crud.data" + :tree-props="{children: 'children', hasChildren: 'hasChildren'}" + row-key="id" + @select="crud.selectChange" + @select-all="crud.selectAllChange" + @selection-change="crud.selectionChangeHandler" + > + <el-table-column type="selection" width="55" /> + <el-table-column :show-overflow-tooltip="true" label="菜单标题" width="125px" prop="title" /> + <el-table-column prop="icon" label="图标" align="center" width="60px"> + <template slot-scope="scope"> + <svg-icon :icon-class="scope.row.icon ? scope.row.icon : ''" /> + </template> + </el-table-column> + <el-table-column prop="menuSort" align="center" label="排序"> + <template slot-scope="scope"> + {{ scope.row.menuSort }} + </template> + </el-table-column> + <el-table-column :show-overflow-tooltip="true" prop="permission" label="权限标识" /> + <el-table-column :show-overflow-tooltip="true" prop="component" label="组件路径" /> + <el-table-column prop="iFrame" label="外链" width="75px"> + <template slot-scope="scope"> + <span v-if="scope.row.iFrame">是</span> + <span v-else>否</span> + </template> + </el-table-column> + <el-table-column prop="cache" label="缓存" width="75px"> + <template slot-scope="scope"> + <span v-if="scope.row.cache">是</span> + <span v-else>否</span> + </template> + </el-table-column> + <el-table-column prop="hidden" label="可见" width="75px"> + <template slot-scope="scope"> + <span v-if="scope.row.hidden">否</span> + <span v-else>是</span> + </template> + </el-table-column> + <el-table-column prop="createTime" label="创建日期" width="135px" /> + <el-table-column v-if="checkPer(['admin','menu:edit','menu:del'])" label="操作" width="130px" align="center" fixed="right"> + <template slot-scope="scope"> + <udOperation + :data="scope.row" + :permission="permission" + msg="确定删除吗,如果存在下级节点则一并删除,此操作不能撤销!" + /> + </template> + </el-table-column> + </el-table> + </div> +</template> + +<script> +import crudMenu from '@/api/system/menu' +import IconSelect from '@/components/IconSelect' +import Treeselect from '@riophae/vue-treeselect' +import '@riophae/vue-treeselect/dist/vue-treeselect.css' +import { LOAD_CHILDREN_OPTIONS } from '@riophae/vue-treeselect' +import CRUD, { presenter, header, form, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import udOperation from '@crud/UD.operation' +import DateRangePicker from '@/components/DateRangePicker' + +// crud交由presenter持有 +const defaultForm = { id: null, title: null, menuSort: 999, path: null, component: null, componentName: null, iFrame: false, roles: [], pid: 0, icon: null, cache: false, hidden: false, type: 0, permission: null } +export default { + name: 'Menu', + components: { Treeselect, IconSelect, crudOperation, rrOperation, udOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '菜单', url: 'api/menus', crudMethod: { ...crudMenu }}) + }, + mixins: [presenter(), header(), form(defaultForm), crud()], + data() { + return { + menus: [], + permission: { + add: ['admin', 'menu:add'], + edit: ['admin', 'menu:edit'], + del: ['admin', 'menu:del'] + }, + rules: { + title: [ + { required: true, message: '请输入标题', trigger: 'blur' } + ], + path: [ + { required: true, message: '请输入地址', trigger: 'blur' } + ] + } + } + }, + methods: { + // 新增与编辑前做的操作 + [CRUD.HOOK.afterToCU](crud, form) { + this.menus = [] + if (form.id != null) { + if (form.pid === null) { + form.pid = 0 + } + this.getSupDepts(form.id) + } else { + this.menus.push({ id: 0, label: '顶级类目', children: null }) + } + }, + getMenus(tree, treeNode, resolve) { + const params = { pid: tree.id } + setTimeout(() => { + crudMenu.getMenus(params).then(res => { + resolve(res.content) + }) + }, 100) + }, + getSupDepts(id) { + crudMenu.getMenuSuperior(id).then(res => { + const children = res.map(function(obj) { + if (!obj.leaf && !obj.children) { + obj.children = null + } + return obj + }) + this.menus = [{ id: 0, label: '顶级类目', children: children }] + }) + }, + loadMenus({ action, parentNode, callback }) { + if (action === LOAD_CHILDREN_OPTIONS) { + crudMenu.getMenusTree(parentNode.id).then(res => { + parentNode.children = res.map(function(obj) { + if (!obj.leaf) { + obj.children = null + } + return obj + }) + setTimeout(() => { + callback() + }, 100) + }) + } + }, + // 选中图标 + selected(name) { + this.form.icon = name + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> + ::v-deep .el-input-number .el-input__inner { + text-align: left; + } + ::v-deep .vue-treeselect__control,::v-deep .vue-treeselect__placeholder,::v-deep .vue-treeselect__single-value { + height: 30px; + line-height: 30px; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/role/index.vue b/UI source code/dns_mapping_ui-master/src/views/system/role/index.vue new file mode 100644 index 0000000..242ed1a --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/role/index.vue @@ -0,0 +1,360 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.blurry" size="small" clearable placeholder="输入名称或者描述搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <rrOperation /> + </div> + <crudOperation :permission="permission" /> + </div> + <!-- 表单渲染 --> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="520px"> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="80px"> + <el-form-item label="角色名称" prop="name"> + <el-input v-model="form.name" style="width: 380px;" /> + </el-form-item> + <el-form-item label="角色级别" prop="level"> + <el-input-number v-model.number="form.level" :min="1" controls-position="right" style="width: 145px;" /> + </el-form-item> + <el-form-item label="数据范围" prop="dataScope"> + <el-select v-model="form.dataScope" style="width: 140px" placeholder="请选择数据范围" @change="changeScope"> + <el-option + v-for="item in dateScopes" + :key="item" + :label="item" + :value="item" + /> + </el-select> + </el-form-item> + <el-form-item v-if="form.dataScope === '自定义'" label="数据权限" prop="depts"> + <treeselect + v-model="deptDatas" + :load-options="loadDepts" + :options="depts" + multiple + style="width: 380px" + placeholder="请选择" + /> + </el-form-item> + <el-form-item label="描述信息" prop="description"> + <el-input v-model="form.description" style="width: 380px;" rows="5" type="textarea" /> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <el-row :gutter="15"> + <!--角色管理--> + <el-col :xs="24" :sm="24" :md="16" :lg="16" :xl="17" style="margin-bottom: 10px"> + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <span class="role-span">角色列表</span> + </div> + <el-table ref="table" v-loading="crud.loading" highlight-current-row style="width: 100%;" :data="crud.data" @selection-change="crud.selectionChangeHandler" @current-change="handleCurrentChange"> + <el-table-column :selectable="checkboxT" type="selection" width="55" /> + <el-table-column prop="name" label="名称" /> + <el-table-column prop="dataScope" label="数据权限" /> + <el-table-column prop="level" label="角色级别" /> + <el-table-column :show-overflow-tooltip="true" prop="description" label="描述" /> + <el-table-column :show-overflow-tooltip="true" width="135px" prop="createTime" label="创建日期" /> + <el-table-column v-if="checkPer(['admin','roles:edit','roles:del'])" label="操作" width="130px" align="center" fixed="right"> + <template slot-scope="scope"> + <udOperation + v-if="scope.row.level >= level" + :data="scope.row" + :permission="permission" + /> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </el-card> + </el-col> + <!-- 菜单授权 --> + <el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="7"> + <el-card class="box-card" shadow="never"> + <div slot="header" class="clearfix"> + <el-tooltip class="item" effect="dark" content="选择指定角色分配菜单" placement="top"> + <span class="role-span">菜单分配</span> + </el-tooltip> + <el-button + v-permission="['admin','roles:edit']" + :disabled="!showButton" + :loading="menuLoading" + icon="el-icon-check" + size="mini" + style="float: right; padding: 6px 9px" + type="primary" + @click="saveMenu" + >保存</el-button> + </div> + <el-tree + ref="menu" + lazy + :data="menus" + :default-checked-keys="menuIds" + :load="getMenuDatas" + :props="defaultProps" + check-strictly + accordion + show-checkbox + node-key="id" + @check="menuChange" + /> + </el-card> + </el-col> + </el-row> + </div> +</template> + +<script> +import crudRoles from '@/api/system/role' +import { getDepts, getDeptSuperior } from '@/api/system/dept' +import { getMenusTree, getChild } from '@/api/system/menu' +import CRUD, { presenter, header, form, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import udOperation from '@crud/UD.operation' +import pagination from '@crud/Pagination' +import Treeselect from '@riophae/vue-treeselect' +import '@riophae/vue-treeselect/dist/vue-treeselect.css' +import { LOAD_CHILDREN_OPTIONS } from '@riophae/vue-treeselect' +import DateRangePicker from '@/components/DateRangePicker' + +const defaultForm = { id: null, name: null, depts: [], description: null, dataScope: '全部', level: 3 } +export default { + name: 'Role', + components: { Treeselect, pagination, crudOperation, rrOperation, udOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '角色', url: 'api/roles', sort: 'level,asc', crudMethod: { ...crudRoles }}) + }, + mixins: [presenter(), header(), form(defaultForm), crud()], + data() { + return { + defaultProps: { children: 'children', label: 'label', isLeaf: 'leaf' }, + dateScopes: ['全部', '本级', '自定义'], level: 3, + currentId: 0, menuLoading: false, showButton: false, + menus: [], menuIds: [], depts: [], deptDatas: [], // 多选时使用 + permission: { + add: ['admin', 'roles:add'], + edit: ['admin', 'roles:edit'], + del: ['admin', 'roles:del'] + }, + rules: { + name: [ + { required: true, message: '请输入名称', trigger: 'blur' } + ], + permission: [ + { required: true, message: '请输入权限', trigger: 'blur' } + ] + } + } + }, + created() { + crudRoles.getLevel().then(data => { + this.level = data.level + }) + }, + methods: { + getMenuDatas(node, resolve) { + setTimeout(() => { + getMenusTree(node.data.id ? node.data.id : 0).then(res => { + resolve(res) + }) + }, 100) + }, + [CRUD.HOOK.afterRefresh]() { + this.$refs.menu.setCheckedKeys([]) + }, + // 新增前初始化部门信息 + [CRUD.HOOK.beforeToAdd](crud, form) { + this.deptDatas = [] + form.menus = null + }, + // 编辑前初始化自定义数据权限的部门信息 + [CRUD.HOOK.beforeToEdit](crud, form) { + this.deptDatas = [] + if (form.dataScope === '自定义') { + this.getSupDepts(form.depts) + } + const _this = this + form.depts.forEach(function(dept) { + _this.deptDatas.push(dept.id) + }) + // 将角色的菜单清空,避免日志入库数据过长 + form.menus = null + }, + // 提交前做的操作 + [CRUD.HOOK.afterValidateCU](crud) { + if (crud.form.dataScope === '自定义' && this.deptDatas.length === 0) { + this.$message({ + message: '自定义数据权限不能为空', + type: 'warning' + }) + return false + } else if (crud.form.dataScope === '自定义') { + const depts = [] + this.deptDatas.forEach(function(data) { + const dept = { id: data } + depts.push(dept) + }) + crud.form.depts = depts + } else { + crud.form.depts = [] + } + return true + }, + // 触发单选 + handleCurrentChange(val) { + if (val) { + const _this = this + // 清空菜单的选中 + this.$refs.menu.setCheckedKeys([]) + // 保存当前的角色id + this.currentId = val.id + // 初始化默认选中的key + this.menuIds = [] + val.menus.forEach(function(data) { + _this.menuIds.push(data.id) + }) + this.showButton = true + } + }, + menuChange(menu) { + // 获取该节点的所有子节点,id 包含自身 + getChild(menu.id).then(childIds => { + // 判断是否在 menuIds 中,如果存在则删除,否则添加 + if (this.menuIds.indexOf(menu.id) !== -1) { + for (let i = 0; i < childIds.length; i++) { + const index = this.menuIds.indexOf(childIds[i]) + if (index !== -1) { + this.menuIds.splice(index, 1) + } + } + } else { + for (let i = 0; i < childIds.length; i++) { + const index = this.menuIds.indexOf(childIds[i]) + if (index === -1) { + this.menuIds.push(childIds[i]) + } + } + } + this.$refs.menu.setCheckedKeys(this.menuIds) + }) + }, + // 保存菜单 + saveMenu() { + this.menuLoading = true + const role = { id: this.currentId, menus: [] } + // 得到已选中的 key 值 + this.menuIds.forEach(function(id) { + const menu = { id: id } + role.menus.push(menu) + }) + crudRoles.editMenu(role).then(() => { + this.crud.notify('保存成功', CRUD.NOTIFICATION_TYPE.SUCCESS) + this.menuLoading = false + this.update() + }).catch(err => { + this.menuLoading = false + console.log(err.response.data.message) + }) + }, + // 改变数据 + update() { + // 无刷新更新 表格数据 + crudRoles.get(this.currentId).then(res => { + for (let i = 0; i < this.crud.data.length; i++) { + if (res.id === this.crud.data[i].id) { + this.crud.data[i] = res + break + } + } + }) + }, + // 获取部门数据 + getDepts() { + getDepts({ enabled: true }).then(res => { + this.depts = res.content.map(function(obj) { + if (obj.hasChildren) { + obj.children = null + } + return obj + }) + }) + }, + getSupDepts(depts) { + const ids = [] + depts.forEach(dept => { + ids.push(dept.id) + }) + getDeptSuperior(ids).then(res => { + const date = res.content + this.buildDepts(date) + this.depts = date + }) + }, + buildDepts(depts) { + depts.forEach(data => { + if (data.children) { + this.buildDepts(data.children) + } + if (data.hasChildren && !data.children) { + data.children = null + } + }) + }, + // 获取弹窗内部门数据 + loadDepts({ action, parentNode, callback }) { + if (action === LOAD_CHILDREN_OPTIONS) { + getDepts({ enabled: true, pid: parentNode.id }).then(res => { + parentNode.children = res.content.map(function(obj) { + if (obj.hasChildren) { + obj.children = null + } + return obj + }) + setTimeout(() => { + callback() + }, 200) + }) + } + }, + // 如果数据权限为自定义则获取部门数据 + changeScope() { + if (this.form.dataScope === '自定义') { + this.getDepts() + } + }, + checkboxT(row) { + return row.level >= this.level + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss"> + .role-span { + font-weight: bold;color: #303133; + font-size: 15px; + } +</style> + +<style rel="stylesheet/scss" lang="scss" scoped> + ::v-deep .el-input-number .el-input__inner { + text-align: left; + } + ::v-deep .vue-treeselect__multi-value{ + margin-bottom: 0; + } + ::v-deep .vue-treeselect__multi-value-item{ + border: 0; + padding: 0; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/timing/index.vue b/UI source code/dns_mapping_ui-master/src/views/system/timing/index.vue new file mode 100644 index 0000000..bb3bf77 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/timing/index.vue @@ -0,0 +1,210 @@ +<template> + <div class="app-container"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.jobName" clearable size="small" placeholder="输入任务名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <rrOperation /> + </div> + <crudOperation :permission="permission"> + <!-- 任务日志 --> + <el-button + slot="right" + class="filter-item" + size="mini" + type="info" + icon="el-icon-tickets" + @click="doLog" + >日志</el-button> + </crudOperation> + <Log ref="log" /> + </div> + <!--Form表单--> + <el-dialog :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" append-to-body width="730px"> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="100px"> + <el-form-item label="任务名称" prop="jobName"> + <el-input v-model="form.jobName" style="width: 220px;" /> + </el-form-item> + <el-form-item label="任务描述" prop="description"> + <el-input v-model="form.description" style="width: 220px;" /> + </el-form-item> + <el-form-item label="Bean名称" prop="beanName"> + <el-input v-model="form.beanName" style="width: 220px;" /> + </el-form-item> + <el-form-item label="执行方法" prop="methodName"> + <el-input v-model="form.methodName" style="width: 220px;" /> + </el-form-item> + <el-form-item label="Cron表达式" prop="cronExpression"> + <el-input v-model="form.cronExpression" style="width: 220px;" /> + </el-form-item> + <el-form-item label="子任务ID"> + <el-input v-model="form.subTask" placeholder="多个用逗号隔开,按顺序执行" style="width: 220px;" /> + </el-form-item> + <el-form-item label="任务负责人" prop="personInCharge"> + <el-input v-model="form.personInCharge" style="width: 220px;" /> + </el-form-item> + <el-form-item label="告警邮箱" prop="email"> + <el-input v-model="form.email" placeholder="多个邮箱用逗号隔开" style="width: 220px;" /> + </el-form-item> + <el-form-item label="失败后暂停"> + <el-radio-group v-model="form.pauseAfterFailure" style="width: 220px"> + <el-radio :label="true">是</el-radio> + <el-radio :label="false">否</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="任务状态"> + <el-radio-group v-model="form.isPause" style="width: 220px"> + <el-radio :label="false">启用</el-radio> + <el-radio :label="true">暂停</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="参数内容"> + <el-input v-model="form.params" style="width: 556px;" rows="4" type="textarea" /> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> + <el-table-column :selectable="checkboxT" type="selection" width="55" /> + <el-table-column :show-overflow-tooltip="true" prop="id" label="任务ID" /> + <el-table-column :show-overflow-tooltip="true" prop="jobName" label="任务名称" /> + <el-table-column :show-overflow-tooltip="true" prop="beanName" label="Bean名称" /> + <el-table-column :show-overflow-tooltip="true" prop="methodName" label="执行方法" /> + <el-table-column :show-overflow-tooltip="true" prop="params" label="参数" /> + <el-table-column :show-overflow-tooltip="true" prop="cronExpression" label="cron表达式" /> + <el-table-column :show-overflow-tooltip="true" prop="isPause" width="90px" label="状态"> + <template slot-scope="scope"> + <el-tag :type="scope.row.isPause ? 'warning' : 'success'">{{ scope.row.isPause ? '已暂停' : '运行中' }}</el-tag> + </template> + </el-table-column> + <el-table-column :show-overflow-tooltip="true" prop="description" width="150px" label="描述" /> + <el-table-column :show-overflow-tooltip="true" prop="createTime" width="136px" label="创建日期" /> + <el-table-column v-if="checkPer(['admin','timing:edit','timing:del'])" label="操作" width="170px" align="center" fixed="right"> + <template slot-scope="scope"> + <el-button v-permission="['admin','timing:edit']" size="mini" style="margin-right: 3px;" type="text" @click="crud.toEdit(scope.row)">编辑</el-button> + <el-button v-permission="['admin','timing:edit']" style="margin-left: -2px" type="text" size="mini" @click="execute(scope.row.id)">执行</el-button> + <el-button v-permission="['admin','timing:edit']" style="margin-left: 3px" type="text" size="mini" @click="updateStatus(scope.row.id,scope.row.isPause ? '恢复' : '暂停')"> + {{ scope.row.isPause ? '恢复' : '暂停' }} + </el-button> + <el-popover + :ref="scope.row.id" + v-permission="['admin','timing:del']" + placement="top" + width="200" + > + <p>确定停止并删除该任务吗?</p> + <div style="text-align: right; margin: 0"> + <el-button size="mini" type="text" @click="$refs[scope.row.id].doClose()">取消</el-button> + <el-button :loading="delLoading" type="primary" size="mini" @click="delMethod(scope.row.id)">确定</el-button> + </div> + <el-button slot="reference" type="text" size="mini">删除</el-button> + </el-popover> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> +import crudJob from '@/api/system/timing' +import Log from './log' +import CRUD, { presenter, header, form, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import pagination from '@crud/Pagination' +import DateRangePicker from '@/components/DateRangePicker' + +const defaultForm = { id: null, jobName: null, subTask: null, beanName: null, methodName: null, params: null, cronExpression: null, pauseAfterFailure: true, isPause: false, personInCharge: null, email: null, description: null } +export default { + name: 'Timing', + components: { Log, pagination, crudOperation, rrOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '定时任务', url: 'api/jobs', crudMethod: { ...crudJob }}) + }, + mixins: [presenter(), header(), form(defaultForm), crud()], + data() { + return { + delLoading: false, + permission: { + add: ['admin', 'timing:add'], + edit: ['admin', 'timing:edit'], + del: ['admin', 'timing:del'] + }, + rules: { + jobName: [ + { required: true, message: '请输入任务名称', trigger: 'blur' } + ], + description: [ + { required: true, message: '请输入任务描述', trigger: 'blur' } + ], + beanName: [ + { required: true, message: '请输入Bean名称', trigger: 'blur' } + ], + methodName: [ + { required: true, message: '请输入方法名称', trigger: 'blur' } + ], + cronExpression: [ + { required: true, message: '请输入Cron表达式', trigger: 'blur' } + ], + personInCharge: [ + { required: true, message: '请输入负责人名称', trigger: 'blur' } + ] + } + } + }, + methods: { + // 执行 + execute(id) { + crudJob.execution(id).then(res => { + this.crud.notify('执行成功', CRUD.NOTIFICATION_TYPE.SUCCESS) + }).catch(err => { + console.log(err.response.data.message) + }) + }, + // 改变状态 + updateStatus(id, status) { + if (status === '恢复') { + this.updateParams(id) + } + crudJob.updateIsPause(id).then(res => { + this.crud.toQuery() + this.crud.notify(status + '成功', CRUD.NOTIFICATION_TYPE.SUCCESS) + }).catch(err => { + console.log(err.response.data.message) + }) + }, + updateParams(id) { + console.log(id) + }, + delMethod(id) { + this.delLoading = true + crudJob.del([id]).then(() => { + this.delLoading = false + this.$refs[id].doClose() + this.crud.dleChangePage(1) + this.crud.delSuccessNotify() + this.crud.toQuery() + }).catch(() => { + this.delLoading = false + this.$refs[id].doClose() + }) + }, + // 显示日志 + doLog() { + this.$refs.log.dialog = true + this.$refs.log.doInit() + }, + checkboxT(row, rowIndex) { + return row.id !== 1 + } + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/timing/log.vue b/UI source code/dns_mapping_ui-master/src/views/system/timing/log.vue new file mode 100644 index 0000000..09c32ef --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/timing/log.vue @@ -0,0 +1,104 @@ +<template> + <el-dialog :visible.sync="dialog" append-to-body title="执行日志" width="88%"> + <!-- 搜索 --> + <div class="head-container"> + <el-input v-model="query.jobName" clearable size="small" placeholder="输入任务名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <el-select v-model="query.isSuccess" placeholder="日志状态" clearable size="small" class="filter-item" style="width: 110px" @change="toQuery"> + <el-option v-for="item in enabledTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" /> + </el-select> + <el-button class="filter-item" size="mini" type="success" icon="el-icon-search" @click="toQuery">搜索</el-button> + <!-- 导出 --> + <div style="display: inline-block;"> + <el-button + :loading="downloadLoading" + size="mini" + class="filter-item" + type="warning" + icon="el-icon-download" + @click="downloadMethod" + >导出</el-button> + </div> + </div> + <!--表格渲染--> + <el-table v-loading="loading" :data="data" style="width: 100%;margin-top: -10px;"> + <el-table-column :show-overflow-tooltip="true" prop="jobName" label="任务名称" /> + <el-table-column :show-overflow-tooltip="true" prop="beanName" label="Bean名称" /> + <el-table-column :show-overflow-tooltip="true" prop="methodName" label="执行方法" /> + <el-table-column :show-overflow-tooltip="true" prop="params" width="120px" label="参数" /> + <el-table-column :show-overflow-tooltip="true" prop="cronExpression" label="cron表达式" /> + <el-table-column prop="createTime" label="异常详情" width="110px"> + <template slot-scope="scope"> + <el-button v-show="scope.row.exceptionDetail" size="mini" type="text" @click="info(scope.row.exceptionDetail)">查看详情</el-button> + </template> + </el-table-column> + <el-table-column :show-overflow-tooltip="true" align="center" prop="time" width="100px" label="耗时(毫秒)" /> + <el-table-column align="center" prop="isSuccess" width="80px" label="状态"> + <template slot-scope="scope"> + <el-tag :type="scope.row.isSuccess ? 'success' : 'danger'">{{ scope.row.isSuccess ? '成功' : '失败' }}</el-tag> + </template> + </el-table-column> + <el-table-column :show-overflow-tooltip="true" prop="createTime" label="创建日期" /> + </el-table> + <el-dialog :visible.sync="errorDialog" append-to-body title="异常详情" width="85%"> + <pre v-highlightjs="errorInfo"><code class="java" /></pre> + </el-dialog> + <!--分页组件--> + <el-pagination + :total="total" + :current-page="page + 1" + :page-size="6" + style="margin-top:8px;" + layout="total, prev, pager, next" + @size-change="sizeChange" + @current-change="pageChange" + /> + </el-dialog> +</template> + +<script> +import crud from '@/mixins/crud' +import DateRangePicker from '@/components/DateRangePicker' +export default { + components: { DateRangePicker }, + mixins: [crud], + data() { + return { + title: '任务日志', + errorInfo: '', errorDialog: false, + enabledTypeOptions: [ + { key: 'true', display_name: '成功' }, + { key: 'false', display_name: '失败' } + ] + } + }, + methods: { + doInit() { + this.$nextTick(() => { + this.init() + }) + }, + // 获取数据前设置好接口地址 + beforeInit() { + this.url = 'api/jobs/logs' + this.size = 6 + return true + }, + // 异常详情 + info(errorInfo) { + this.errorInfo = errorInfo + this.errorDialog = true + } + } +} +</script> + +<style scoped> + .java.hljs{ + color: #444; + background: #ffffff !important; + } + ::v-deep .el-dialog__body{ + padding: 0 20px 10px 20px !important; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/user/center.vue b/UI source code/dns_mapping_ui-master/src/views/system/user/center.vue new file mode 100644 index 0000000..1cc5681 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/user/center.vue @@ -0,0 +1,221 @@ +<template> + <div class="app-container"> + <el-row :gutter="20"> + <el-col :xs="24" :sm="24" :md="8" :lg="6" :xl="5" style="margin-bottom: 10px"> + <el-card class="box-card"> + <div slot="header" class="clearfix"> + <span>个人信息</span> + </div> + <div> + <div style="text-align: center"> + <div class="el-upload"> + <img :src="user.avatarName ? baseApi + '/avatar/' + user.avatarName : Avatar" title="点击上传头像" class="avatar" @click="toggleShow"> + <myUpload + v-model="show" + :headers="headers" + :url="updateAvatarApi" + @crop-upload-success="cropUploadSuccess" + /> + </div> + </div> + <ul class="user-info"> + <li><div style="height: 100%"><svg-icon icon-class="login" /> 登录账号<div class="user-right">{{ user.username }}</div></div></li> + <li><svg-icon icon-class="user1" /> 用户昵称 <div class="user-right">{{ user.nickName }}</div></li> + <li><svg-icon icon-class="dept" /> 所属部门 <div class="user-right"> {{ user.dept.name }}</div></li> + <li><svg-icon icon-class="phone" /> 手机号码 <div class="user-right">{{ user.phone }}</div></li> + <li><svg-icon icon-class="email" /> 用户邮箱 <div class="user-right">{{ user.email }}</div></li> + <li> + <svg-icon icon-class="anq" /> 安全设置 + <div class="user-right"> + <a @click="$refs.pass.dialog = true">修改密码</a> + <a @click="$refs.email.dialog = true">修改邮箱</a> + </div> + </li> + </ul> + </div> + </el-card> + </el-col> + <el-col :xs="24" :sm="24" :md="16" :lg="18" :xl="19"> + <!-- 用户资料 --> + <el-card class="box-card"> + <el-tabs v-model="activeName" @tab-click="handleClick"> + <el-tab-pane label="用户资料" name="first"> + <el-form ref="form" :model="form" :rules="rules" style="margin-top: 10px;" size="small" label-width="65px"> + <el-form-item label="昵称" prop="nickName"> + <el-input v-model="form.nickName" style="width: 35%" /> + <span style="color: #C0C0C0;margin-left: 10px;">用户昵称不作为登录使用</span> + </el-form-item> + <el-form-item label="手机号" prop="phone"> + <el-input v-model="form.phone" style="width: 35%;" /> + <span style="color: #C0C0C0;margin-left: 10px;">手机号码不能重复</span> + </el-form-item> + <el-form-item label="性别"> + <el-radio-group v-model="form.gender" style="width: 178px"> + <el-radio label="男">男</el-radio> + <el-radio label="女">女</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label=""> + <el-button :loading="saveLoading" size="mini" type="primary" @click="doSubmit">保存配置</el-button> + </el-form-item> + </el-form> + </el-tab-pane> + <!-- 操作日志 --> + <el-tab-pane label="操作日志" name="second"> + <el-table v-loading="loading" :data="data" style="width: 100%;"> + <el-table-column prop="description" label="行为" /> + <el-table-column prop="requestIp" label="IP" /> + <el-table-column :show-overflow-tooltip="true" prop="address" label="IP来源" /> + <el-table-column prop="browser" label="浏览器" /> + <el-table-column prop="time" label="请求耗时" align="center"> + <template slot-scope="scope"> + <el-tag v-if="scope.row.time <= 300">{{ scope.row.time }}ms</el-tag> + <el-tag v-else-if="scope.row.time <= 1000" type="warning">{{ scope.row.time }}ms</el-tag> + <el-tag v-else type="danger">{{ scope.row.time }}ms</el-tag> + </template> + </el-table-column> + <el-table-column + align="right" + > + <template slot="header"> + <div style="display:inline-block;float: right;cursor: pointer" @click="init">创建日期<i class="el-icon-refresh" style="margin-left: 40px" /></div> + </template> + <template slot-scope="scope"> + <span>{{ scope.row.createTime }}</span> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <el-pagination + :total="total" + :current-page="page + 1" + style="margin-top: 8px;" + layout="total, prev, pager, next, sizes" + @size-change="sizeChange" + @current-change="pageChange" + /> + </el-tab-pane> + </el-tabs> + </el-card> + </el-col> + </el-row> + <updateEmail ref="email" :email="user.email" /> + <updatePass ref="pass" /> + </div> +</template> + +<script> +import myUpload from 'vue-image-crop-upload' +import { mapGetters } from 'vuex' +import updatePass from './center/updatePass' +import updateEmail from './center/updateEmail' +import { getToken } from '@/utils/auth' +import store from '@/store' +import { isvalidPhone } from '@/utils/validate' +import crud from '@/mixins/crud' +import { editUser } from '@/api/system/user' +import Avatar from '@/assets/images/avatar.png' +export default { + name: 'Center', + components: { updatePass, updateEmail, myUpload }, + mixins: [crud], + data() { + // 自定义验证 + const validPhone = (rule, value, callback) => { + if (!value) { + callback(new Error('请输入电话号码')) + } else if (!isvalidPhone(value)) { + callback(new Error('请输入正确的11位手机号码')) + } else { + callback() + } + } + return { + show: false, + Avatar: Avatar, + activeName: 'first', + saveLoading: false, + headers: { + 'Authorization': getToken() + }, + form: {}, + rules: { + nickName: [ + { required: true, message: '请输入用户昵称', trigger: 'blur' }, + { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' } + ], + phone: [ + { required: true, trigger: 'blur', validator: validPhone } + ] + } + } + }, + computed: { + ...mapGetters([ + 'user', + 'updateAvatarApi', + 'baseApi' + ]) + }, + created() { + this.form = { id: this.user.id, nickName: this.user.nickName, gender: this.user.gender, phone: this.user.phone } + store.dispatch('GetInfo').then(() => {}) + }, + methods: { + toggleShow() { + this.show = !this.show + }, + handleClick(tab, event) { + if (tab.name === 'second') { + this.init() + } + }, + beforeInit() { + this.url = 'api/logs/user' + return true + }, + cropUploadSuccess(jsonData, field) { + store.dispatch('GetInfo').then(() => {}) + }, + doSubmit() { + if (this.$refs['form']) { + this.$refs['form'].validate((valid) => { + if (valid) { + this.saveLoading = true + editUser(this.form).then(() => { + this.editSuccessNotify() + store.dispatch('GetInfo').then(() => {}) + this.saveLoading = false + }).catch(() => { + this.saveLoading = false + }) + } + }) + } + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss"> + .avatar { + width: 120px; + height: 120px; + border-radius: 50%; + } + .user-info { + padding-left: 0; + list-style: none; + li{ + border-bottom: 1px solid #F0F3F4; + padding: 11px 0; + font-size: 13px; + } + .user-right { + float: right; + a{ + color: #317EF3; + } + } + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/user/center/updateEmail.vue b/UI source code/dns_mapping_ui-master/src/views/system/user/center/updateEmail.vue new file mode 100644 index 0000000..b246684 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/user/center/updateEmail.vue @@ -0,0 +1,137 @@ +<template> + <div style="display: inline-block;"> + <el-dialog :visible.sync="dialog" :close-on-click-modal="false" :before-close="cancel" :title="title" append-to-body width="475px" @close="cancel"> + <el-form ref="form" :model="form" :rules="rules" size="small" label-width="88px"> + <el-form-item label="新邮箱" prop="email"> + <el-input v-model="form.email" auto-complete="on" style="width: 200px;" /> + <el-button :loading="codeLoading" :disabled="isDisabled" size="small" @click="sendCode">{{ buttonName }}</el-button> + </el-form-item> + <el-form-item label="验证码" prop="code"> + <el-input v-model="form.code" style="width: 320px;" /> + </el-form-item> + <el-form-item label="当前密码" prop="pass"> + <el-input v-model="form.pass" type="password" style="width: 320px;" /> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="cancel">取消</el-button> + <el-button :loading="loading" type="primary" @click="doSubmit">确认</el-button> + </div> + </el-dialog> + </div> +</template> + +<script> +import store from '@/store' +import { validEmail } from '@/utils/validate' +import { updateEmail } from '@/api/system/user' +import { resetEmail } from '@/api/system/code' +export default { + props: { + email: { + type: String, + required: true + } + }, + data() { + const validMail = (rule, value, callback) => { + if (value === '' || value === null) { + callback(new Error('新邮箱不能为空')) + } else if (value === this.email) { + callback(new Error('新邮箱不能与旧邮箱相同')) + } else if (validEmail(value)) { + callback() + } else { + callback(new Error('邮箱格式错误')) + } + } + return { + loading: false, dialog: false, title: '修改邮箱', form: { pass: '', email: '', code: '' }, + user: { email: '', password: '' }, codeLoading: false, + buttonName: '获取验证码', isDisabled: false, time: 60, + rules: { + pass: [ + { required: true, message: '当前密码不能为空', trigger: 'blur' } + ], + email: [ + { required: true, validator: validMail, trigger: 'blur' } + ], + code: [ + { required: true, message: '验证码不能为空', trigger: 'blur' } + ] + } + } + }, + methods: { + cancel() { + this.resetForm() + }, + sendCode() { + if (this.form.email && this.form.email !== this.email) { + this.codeLoading = true + this.buttonName = '验证码发送中' + const _this = this + resetEmail(this.form.email).then(res => { + this.$message({ + showClose: true, + message: '发送成功,验证码有效期5分钟', + type: 'success' + }) + this.codeLoading = false + this.isDisabled = true + this.buttonName = this.time-- + '秒后重新发送' + this.timer = window.setInterval(function() { + _this.buttonName = _this.time + '秒后重新发送' + --_this.time + if (_this.time < 0) { + _this.buttonName = '重新发送' + _this.time = 60 + _this.isDisabled = false + window.clearInterval(_this.timer) + } + }, 1000) + }).catch(err => { + this.resetForm() + this.codeLoading = false + console.log(err.response.data.message) + }) + } + }, + doSubmit() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.loading = true + updateEmail(this.form).then(res => { + this.loading = false + this.resetForm() + this.$notify({ + title: '邮箱修改成功', + type: 'success', + duration: 1500 + }) + store.dispatch('GetInfo').then(() => {}) + }).catch(err => { + this.loading = false + console.log(err.response.data.message) + }) + } else { + return false + } + }) + }, + resetForm() { + this.dialog = false + this.$refs['form'].resetFields() + window.clearInterval(this.timer) + this.time = 60 + this.buttonName = '获取验证码' + this.isDisabled = false + this.form = { pass: '', email: '', code: '' } + } + } +} +</script> + +<style scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/user/center/updatePass.vue b/UI source code/dns_mapping_ui-master/src/views/system/user/center/updatePass.vue new file mode 100644 index 0000000..078ed17 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/user/center/updatePass.vue @@ -0,0 +1,95 @@ +<template> + <div style="display: inline-block"> + <el-dialog :visible.sync="dialog" :close-on-click-modal="false" :before-close="cancel" :title="title" append-to-body width="500px" @close="cancel"> + <el-form ref="form" :model="form" :rules="rules" size="small" label-width="88px"> + <el-form-item label="旧密码" prop="oldPass"> + <el-input v-model="form.oldPass" type="password" auto-complete="on" style="width: 370px;" /> + </el-form-item> + <el-form-item label="新密码" prop="newPass"> + <el-input v-model="form.newPass" type="password" auto-complete="on" style="width: 370px;" /> + </el-form-item> + <el-form-item label="确认密码" prop="confirmPass"> + <el-input v-model="form.confirmPass" type="password" auto-complete="on" style="width: 370px;" /> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="cancel">取消</el-button> + <el-button :loading="loading" type="primary" @click="doSubmit">确认</el-button> + </div> + </el-dialog> + </div> +</template> + +<script> +import store from '@/store' +import { updatePass } from '@/api/system/user' +export default { + data() { + const confirmPass = (rule, value, callback) => { + if (value) { + if (this.form.newPass !== value) { + callback(new Error('两次输入的密码不一致')) + } else { + callback() + } + } else { + callback(new Error('请再次输入密码')) + } + } + return { + loading: false, dialog: false, title: '修改密码', form: { oldPass: '', newPass: '', confirmPass: '' }, + rules: { + oldPass: [ + { required: true, message: '请输入旧密码', trigger: 'blur' } + ], + newPass: [ + { required: true, message: '请输入新密码', trigger: 'blur' }, + { min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' } + ], + confirmPass: [ + { required: true, validator: confirmPass, trigger: 'blur' } + ] + } + } + }, + methods: { + cancel() { + this.resetForm() + }, + doSubmit() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.loading = true + updatePass(this.form).then(res => { + this.resetForm() + this.$notify({ + title: '密码修改成功,请重新登录', + type: 'success', + duration: 1500 + }) + setTimeout(() => { + store.dispatch('LogOut').then(() => { + location.reload() // 为了重新实例化vue-router对象 避免bug + }) + }, 1500) + }).catch(err => { + this.loading = false + console.log(err.response.data.message) + }) + } else { + return false + } + }) + }, + resetForm() { + this.dialog = false + this.$refs['form'].resetFields() + this.form = { oldPass: '', newPass: '', confirmPass: '' } + } + } +} +</script> + +<style scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/system/user/index.vue b/UI source code/dns_mapping_ui-master/src/views/system/user/index.vue new file mode 100644 index 0000000..9017069 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/system/user/index.vue @@ -0,0 +1,484 @@ +<template> + <div class="app-container"> + <el-row :gutter="20"> + <!--侧边部门数据--> + <el-col :xs="9" :sm="6" :md="5" :lg="4" :xl="4"> + <div class="head-container"> + <el-input + v-model="deptName" + clearable + size="small" + placeholder="输入部门名称搜索" + prefix-icon="el-icon-search" + class="filter-item" + @input="getDeptDatas" + /> + </div> + <el-tree + :data="deptDatas" + :load="getDeptDatas" + :props="defaultProps" + :expand-on-click-node="false" + lazy + @node-click="handleNodeClick" + /> + </el-col> + <!--用户数据--> + <el-col :xs="15" :sm="18" :md="19" :lg="20" :xl="20"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input + v-model="query.blurry" + clearable + size="small" + placeholder="输入名称或者邮箱搜索" + style="width: 200px;" + class="filter-item" + @keyup.enter.native="crud.toQuery" + /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <el-select + v-model="query.enabled" + clearable + size="small" + placeholder="状态" + class="filter-item" + style="width: 90px" + @change="crud.toQuery" + > + <el-option + v-for="item in enabledTypeOptions" + :key="item.key" + :label="item.display_name" + :value="item.key" + /> + </el-select> + <rrOperation /> + </div> + <crudOperation show="" :permission="permission" /> + </div> + <!--表单渲染--> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="570px"> + <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="66px"> + <el-form-item label="用户名" prop="username"> + <el-input v-model="form.username" @keydown.native="keydown($event)" /> + </el-form-item> + <el-form-item label="电话" prop="phone"> + <el-input v-model.number="form.phone" /> + </el-form-item> + <el-form-item label="昵称" prop="nickName"> + <el-input v-model="form.nickName" @keydown.native="keydown($event)" /> + </el-form-item> + <el-form-item label="邮箱" prop="email"> + <el-input v-model="form.email" /> + </el-form-item> + <el-form-item label="部门" prop="dept.id"> + <treeselect + v-model="form.dept.id" + :options="depts" + :load-options="loadDepts" + style="width: 178px" + placeholder="选择部门" + /> + </el-form-item> + <el-form-item label="岗位" prop="jobs"> + <el-select + v-model="jobDatas" + style="width: 178px" + multiple + placeholder="请选择" + @remove-tag="deleteTag" + @change="changeJob" + > + <el-option + v-for="item in jobs" + :key="item.name" + :label="item.name" + :value="item.id" + /> + </el-select> + </el-form-item> + <el-form-item label="性别"> + <el-radio-group v-model="form.gender" style="width: 178px"> + <el-radio label="男">男</el-radio> + <el-radio label="女">女</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="状态"> + <el-radio-group v-model="form.enabled" :disabled="form.id === user.id"> + <el-radio + v-for="item in dict.user_status" + :key="item.id" + :label="item.value" + >{{ item.label }}</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item style="margin-bottom: 0;" label="角色" prop="roles"> + <el-select + v-model="roleDatas" + style="width: 437px" + multiple + placeholder="请选择" + @remove-tag="deleteTag" + @change="changeRole" + > + <el-option + v-for="item in roles" + :key="item.name" + :disabled="level !== 1 && item.level <= level" + :label="item.name" + :value="item.id" + /> + </el-select> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> + <el-table-column :selectable="checkboxT" type="selection" width="55" /> + <el-table-column :show-overflow-tooltip="true" prop="username" label="用户名" /> + <el-table-column :show-overflow-tooltip="true" prop="nickName" label="昵称" /> + <el-table-column prop="gender" label="性别" /> + <el-table-column :show-overflow-tooltip="true" prop="phone" width="100" label="电话" /> + <el-table-column :show-overflow-tooltip="true" width="135" prop="email" label="邮箱" /> + <el-table-column :show-overflow-tooltip="true" prop="dept" label="部门"> + <template slot-scope="scope"> + <div>{{ scope.row.dept.name }}</div> + </template> + </el-table-column> + <el-table-column label="状态" align="center" prop="enabled"> + <template slot-scope="scope"> + <el-switch + v-model="scope.row.enabled" + :disabled="user.id === scope.row.id" + active-color="#409EFF" + inactive-color="#F56C6C" + @change="changeEnabled(scope.row, scope.row.enabled)" + /> + </template> + </el-table-column> + <el-table-column :show-overflow-tooltip="true" prop="createTime" width="135" label="创建日期" /> + <el-table-column + v-if="checkPer(['admin','user:edit','user:del'])" + label="操作" + width="115" + align="center" + fixed="right" + > + <template slot-scope="scope"> + <udOperation + :data="scope.row" + :permission="permission" + :disabled-dle="scope.row.id === user.id" + /> + </template> + </el-table-column> + </el-table> + <!--分页组件--> + <pagination /> + </el-col> + </el-row> + </div> +</template> + +<script> +import crudUser from '@/api/system/user' +import { isvalidPhone } from '@/utils/validate' +import { getDepts, getDeptSuperior } from '@/api/system/dept' +import { getAll, getLevel } from '@/api/system/role' +import { getAllJob } from '@/api/system/job' +import CRUD, { presenter, header, form, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import udOperation from '@crud/UD.operation' +import pagination from '@crud/Pagination' +import DateRangePicker from '@/components/DateRangePicker' +import Treeselect from '@riophae/vue-treeselect' +import { mapGetters } from 'vuex' +import '@riophae/vue-treeselect/dist/vue-treeselect.css' +import { LOAD_CHILDREN_OPTIONS } from '@riophae/vue-treeselect' +let userRoles = [] +let userJobs = [] +const defaultForm = { id: null, username: null, nickName: null, gender: '男', email: null, enabled: 'false', roles: [], jobs: [], dept: { id: null }, phone: null } +export default { + name: 'User', + components: { Treeselect, crudOperation, rrOperation, udOperation, pagination, DateRangePicker }, + cruds() { + return CRUD({ title: '用户', url: 'api/users', crudMethod: { ...crudUser }}) + }, + mixins: [presenter(), header(), form(defaultForm), crud()], + // 数据字典 + dicts: ['user_status'], + data() { + // 自定义验证 + const validPhone = (rule, value, callback) => { + if (!value) { + callback(new Error('请输入电话号码')) + } else if (!isvalidPhone(value)) { + callback(new Error('请输入正确的11位手机号码')) + } else { + callback() + } + } + return { + height: document.documentElement.clientHeight - 180 + 'px;', + deptName: '', depts: [], deptDatas: [], jobs: [], level: 3, roles: [], + jobDatas: [], roleDatas: [], // 多选时使用 + defaultProps: { children: 'children', label: 'name', isLeaf: 'leaf' }, + permission: { + add: ['admin', 'user:add'], + edit: ['admin', 'user:edit'], + del: ['admin', 'user:del'] + }, + enabledTypeOptions: [ + { key: 'true', display_name: '激活' }, + { key: 'false', display_name: '锁定' } + ], + rules: { + username: [ + { required: true, message: '请输入用户名', trigger: 'blur' }, + { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' } + ], + nickName: [ + { required: true, message: '请输入用户昵称', trigger: 'blur' }, + { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' } + ], + email: [ + { required: true, message: '请输入邮箱地址', trigger: 'blur' }, + { type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' } + ], + phone: [ + { required: true, trigger: 'blur', validator: validPhone } + ] + } + } + }, + computed: { + ...mapGetters([ + 'user' + ]) + }, + created() { + this.crud.msg.add = '新增成功,默认密码:123456' + }, + mounted: function() { + const that = this + window.onresize = function temp() { + that.height = document.documentElement.clientHeight - 180 + 'px;' + } + }, + methods: { + // 禁止输入空格 + keydown(e) { + if (e.keyCode === 32) { + e.returnValue = false + } + }, + changeRole(value) { + userRoles = [] + value.forEach(function(data, index) { + const role = { id: data } + userRoles.push(role) + }) + }, + changeJob(value) { + userJobs = [] + value.forEach(function(data, index) { + const job = { id: data } + userJobs.push(job) + }) + }, + deleteTag(value) { + userRoles.forEach(function(data, index) { + if (data.id === value) { + userRoles.splice(index, value) + } + }) + }, + // 新增与编辑前做的操作 + [CRUD.HOOK.afterToCU](crud, form) { + this.getRoles() + if (form.id == null) { + this.getDepts() + } else { + this.getSupDepts(form.dept.id) + } + this.getRoleLevel() + this.getJobs() + form.enabled = form.enabled.toString() + }, + // 新增前将多选的值设置为空 + [CRUD.HOOK.beforeToAdd]() { + this.jobDatas = [] + this.roleDatas = [] + }, + // 初始化编辑时候的角色与岗位 + [CRUD.HOOK.beforeToEdit](crud, form) { + this.getJobs(this.form.dept.id) + this.jobDatas = [] + this.roleDatas = [] + userRoles = [] + userJobs = [] + const _this = this + form.roles.forEach(function(role, index) { + _this.roleDatas.push(role.id) + const rol = { id: role.id } + userRoles.push(rol) + }) + form.jobs.forEach(function(job, index) { + _this.jobDatas.push(job.id) + const data = { id: job.id } + userJobs.push(data) + }) + }, + // 提交前做的操作 + [CRUD.HOOK.afterValidateCU](crud) { + if (!crud.form.dept.id) { + this.$message({ + message: '部门不能为空', + type: 'warning' + }) + return false + } else if (this.jobDatas.length === 0) { + this.$message({ + message: '岗位不能为空', + type: 'warning' + }) + return false + } else if (this.roleDatas.length === 0) { + this.$message({ + message: '角色不能为空', + type: 'warning' + }) + return false + } + crud.form.roles = userRoles + crud.form.jobs = userJobs + return true + }, + // 获取左侧部门数据 + getDeptDatas(node, resolve) { + const sort = 'id,desc' + const params = { sort: sort } + if (typeof node !== 'object') { + if (node) { + params['name'] = node + } + } else if (node.level !== 0) { + params['pid'] = node.data.id + } + setTimeout(() => { + getDepts(params).then(res => { + if (resolve) { + resolve(res.content) + } else { + this.deptDatas = res.content + } + }) + }, 100) + }, + getDepts() { + getDepts({ enabled: true }).then(res => { + this.depts = res.content.map(function(obj) { + if (obj.hasChildren) { + obj.children = null + } + return obj + }) + }) + }, + getSupDepts(deptId) { + getDeptSuperior(deptId).then(res => { + const date = res.content + this.buildDepts(date) + this.depts = date + }) + }, + buildDepts(depts) { + depts.forEach(data => { + if (data.children) { + this.buildDepts(data.children) + } + if (data.hasChildren && !data.children) { + data.children = null + } + }) + }, + // 获取弹窗内部门数据 + loadDepts({ action, parentNode, callback }) { + if (action === LOAD_CHILDREN_OPTIONS) { + getDepts({ enabled: true, pid: parentNode.id }).then(res => { + parentNode.children = res.content.map(function(obj) { + if (obj.hasChildren) { + obj.children = null + } + return obj + }) + setTimeout(() => { + callback() + }, 200) + }) + } + }, + // 切换部门 + handleNodeClick(data) { + if (data.pid === 0) { + this.query.deptId = null + } else { + this.query.deptId = data.id + } + this.crud.toQuery() + }, + // 改变状态 + changeEnabled(data, val) { + this.$confirm('此操作将 "' + this.dict.label.user_status[val] + '" ' + data.username + ', 是否继续?', '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + crudUser.edit(data).then(res => { + this.crud.notify(this.dict.label.user_status[val] + '成功', CRUD.NOTIFICATION_TYPE.SUCCESS) + }).catch(() => { + data.enabled = !data.enabled + }) + }).catch(() => { + data.enabled = !data.enabled + }) + }, + // 获取弹窗内角色数据 + getRoles() { + getAll().then(res => { + this.roles = res + }).catch(() => { }) + }, + // 获取弹窗内岗位数据 + getJobs() { + getAllJob().then(res => { + this.jobs = res.content + }).catch(() => { }) + }, + // 获取权限级别 + getRoleLevel() { + getLevel().then(res => { + this.level = res.level + }).catch(() => { }) + }, + checkboxT(row, rowIndex) { + return row.id !== this.user.id + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> + ::v-deep .vue-treeselect__control,::v-deep .vue-treeselect__placeholder,::v-deep .vue-treeselect__single-value { + height: 30px; + line-height: 30px; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/aliPay/config.vue b/UI source code/dns_mapping_ui-master/src/views/tools/aliPay/config.vue new file mode 100644 index 0000000..e7b50d4 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/aliPay/config.vue @@ -0,0 +1,98 @@ +<template> + <el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="100px"> + <el-form-item label="appID" prop="appId"> + <el-input v-model="form.appId" style="width: 40%" /> + <span style="color: #C0C0C0;margin-left: 10px;">应用APPID,收款账号既是APPID对应支付宝账号</span> + </el-form-item> + <el-form-item label="商家账号" prop="sysServiceProviderId"> + <el-input v-model="form.sysServiceProviderId" style="width: 40%;" /> + <span style="color: #C0C0C0;margin-left: 10px;">商家账号</span> + </el-form-item> + <el-form-item label="商户私钥" prop="privateKey"> + <el-input v-model="form.privateKey" type="password" style="width: 40%;" /> + <span style="color: #C0C0C0;margin-left: 10px;">商户私钥,你的PKCS8格式RSA2私钥</span> + </el-form-item> + <el-form-item label="支付宝公钥" prop="publicKey"> + <el-input v-model="form.publicKey" type="password" style="width: 40%;" /> + <span style="color: #C0C0C0;margin-left: 10px;">支付宝公钥</span> + </el-form-item> + <el-form-item label="回调地址" prop="returnUrl"> + <el-input v-model="form.returnUrl" style="width: 40%;" /> + <span style="color: #C0C0C0;margin-left: 10px;">订单完成后返回的地址</span> + </el-form-item> + <el-form-item label="异步通知" prop="notifyUrl"> + <el-input v-model="form.notifyUrl" style="width: 40%;" /> + <span style="color: #C0C0C0;margin-left: 10px;">支付结果异步通知地址</span> + </el-form-item> + <el-form-item label=""> + <el-button :loading="loading" size="medium" type="primary" @click="doSubmit">保存配置</el-button> + </el-form-item> + </el-form> +</template> + +<script> +import { get, update } from '@/api/tools/alipay' +export default { + name: 'Config', + data() { + return { + loading: false, + form: { appId: '', sysServiceProviderId: '', privateKey: '', publicKey: '', returnUrl: '', notifyUrl: '' }, + rules: { + appId: [ + { required: true, message: '请输入appID', trigger: 'blur' } + ], + sysServiceProviderId: [ + { required: true, message: '请输入商家账号', trigger: 'blur' } + ], + privateKey: [ + { required: true, message: '商户私钥不能为空', trigger: 'blur' } + ], + publicKey: [ + { required: true, message: '支付宝公钥不能为空', trigger: 'blur' } + ], + returnUrl: [ + { required: true, message: '回调地址不能为空', trigger: 'blur' } + ], + notifyUrl: [ + { required: true, message: '回调地址不能为空', trigger: 'blur' } + ] + } + } + }, + created() { + this.init() + }, + methods: { + init() { + get().then(res => { + this.form = res + }) + }, + doSubmit() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.loading = true + update(this.form).then(res => { + this.$notify({ + title: '修改成功', + type: 'success', + duration: 2500 + }) + this.loading = false + }).catch(err => { + this.loading = false + console.log(err.response.data.message) + }) + } else { + return false + } + }) + } + } +} +</script> + +<style scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/aliPay/index.vue b/UI source code/dns_mapping_ui-master/src/views/tools/aliPay/index.vue new file mode 100644 index 0000000..5234929 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/aliPay/index.vue @@ -0,0 +1,48 @@ +<template> + <el-tabs v-model="activeName" style="padding-left: 5px;"> + <el-tab-pane label="参数配置" name="first"> + <Config /> + </el-tab-pane> + <el-tab-pane label="支付测试" name="second"> + <ToPay /> + </el-tab-pane> + <el-tab-pane label="使用说明" name="third"> + <div> + <blockquote class="my-blockquote">注意</blockquote> + <pre class="my-code"> +测试所用参数都是沙箱环境,仅供测试使用,申请地址:<a style="color: #00a0e9" href="https://openhome.alipay.com/platform/appDaily.htm?tab=info" target="_blank">支付宝开发平台</a> +如需付款测试,请使用 +密码与支付密码:111111</pre> + <blockquote class="my-blockquote"> 支付设置</blockquote> + <pre class="my-code"> +// 支付提供两个接口, +// PC端与手机端,并且在前端使用代码识别 +if (/(Android)/i.test(navigator.userAgent)){ // 判断是否为Android手机 + url = "/aliPay/toPayAsWeb" +}else if(/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)){ // 判断是否为苹果手机 + url = "/aliPay/toPayAsWeb" +} else { + url = "/aliPay/toPayAsPC" +}</pre> + </div> + </el-tab-pane> + </el-tabs> +</template> + +<script> +import Config from './config' +import ToPay from './toPay' +export default { + name: 'AliPay', + components: { Config, ToPay }, + data() { + return { + activeName: 'second' + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/aliPay/toPay.vue b/UI source code/dns_mapping_ui-master/src/views/tools/aliPay/toPay.vue new file mode 100644 index 0000000..595cf08 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/aliPay/toPay.vue @@ -0,0 +1,86 @@ +<template> + <div> + <el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="90px"> + <el-form-item label="商品名称" prop="subject"> + <el-input v-model="form.subject" style="width: 35%" /> + </el-form-item> + <el-form-item label="商品价格" prop="totalAmount"> + <el-input v-model="form.totalAmount" style="width: 35%" /> + <span style="color: #C0C0C0;margin-left: 10px;">测试允许区间(0,5000]</span> + </el-form-item> + <el-form-item label="商品描述" prop="body"> + <el-input v-model="form.body" style="width: 35%" rows="8" type="textarea" /> + </el-form-item> + <el-form-item label=""> + <el-button :loading="loading" size="medium" type="primary" @click="doSubmit">去支付</el-button> + </el-form-item> + </el-form> + </div> +</template> + +<script> +import { toAliPay } from '@/api/tools/alipay' +export default { + data() { + return { + url: '', + // 新窗口的引用 + newWin: null, + loading: false, form: { subject: '', totalAmount: '', body: '' }, + rules: { + subject: [ + { required: true, message: '商品名称不能为空', trigger: 'blur' } + ], + totalAmount: [ + { required: true, message: '商品价格不能为空', trigger: 'blur' } + ], + body: [ + { required: true, message: '商品描述不能为空', trigger: 'blur' } + ] + } + } + }, + watch: { + url(newVal, oldVal) { + if (newVal && this.newWin) { + this.newWin.sessionStorage.clear() + this.newWin.location.href = newVal + // 重定向后把url和newWin重置 + this.url = '' + this.newWin = null + } + } + }, + methods: { + doSubmit() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.loading = true + // 先打开一个空的新窗口,再请求 + this.newWin = window.open() + let url = '' + if (/(Android)/i.test(navigator.userAgent)) { // 判断是否为Android手机 + url = 'aliPay/toPayAsWeb' + } else if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) { // 判断是否为苹果手机 + url = 'aliPay/toPayAsWeb' + } else { + url = 'aliPay/toPayAsPC' + } + toAliPay(url, this.form).then(res => { + this.loading = false + this.url = res + }).catch(err => { + this.loading = false + console.log(err.response.data.message) + }) + } else { + return false + } + }) + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/email/config.vue b/UI source code/dns_mapping_ui-master/src/views/tools/email/config.vue new file mode 100644 index 0000000..b72b724 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/email/config.vue @@ -0,0 +1,91 @@ +<template> + <el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="100px"> + <el-form-item label="发件人邮箱" prop="fromUser"> + <el-input v-model="form.fromUser" style="width: 40%" /> + <span style="color: #C0C0C0;margin-left: 10px;">Sender mailbox</span> + </el-form-item> + <el-form-item label="发件用户名" prop="user"> + <el-input v-model="form.user" style="width: 40%;" /> + <span style="color: #C0C0C0;margin-left: 10px;">Sender usernamex</span> + </el-form-item> + <el-form-item label="邮箱密码" prop="pass"> + <el-input v-model="form.pass" type="password" style="width: 40%;" /> + <span style="color: #C0C0C0;margin-left: 10px;">email Password</span> + </el-form-item> + <el-form-item label="SMTP地址" prop="host"> + <el-input v-model="form.host" style="width: 40%;" /> + <span style="color: #C0C0C0;margin-left: 10px;">SMTP address</span> + </el-form-item> + <el-form-item label="SMTP端口" prop="port"> + <el-input v-model="form.port" style="width: 40%;" /> + <span style="color: #C0C0C0;margin-left: 10px;">SMTP port</span> + </el-form-item> + <el-form-item label=""> + <el-button :loading="loading" size="medium" type="primary" @click="doSubmit">保存配置</el-button> + </el-form-item> + </el-form> +</template> + +<script> +import { get, update } from '@/api/tools/email' +export default { + name: 'Config', + data() { + return { + loading: false, form: { id: 1, fromUser: '', user: '', pass: '', host: '', port: '', sslEnable: '' }, + rules: { + fromUser: [ + { required: true, message: '请输入发件人邮箱', trigger: 'blur' }, + { type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' } + ], + user: [ + { required: true, message: '请输入发件用户名', trigger: 'blur' } + ], + pass: [ + { required: true, message: '密码不能为空', trigger: 'blur' } + ], + host: [ + { required: true, message: 'SMTP地址不能为空', trigger: 'blur' } + ], + port: [ + { required: true, message: 'SMTP端口不能为空', trigger: 'blur' } + ] + } + } + }, + created() { + this.init() + }, + methods: { + init() { + get().then(res => { + this.form = res + }) + }, + doSubmit() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.loading = true + update(this.form).then(res => { + this.$notify({ + title: '修改成功', + type: 'success', + duration: 2500 + }) + this.loading = false + }).catch(err => { + this.loading = false + console.log(err.response.data.message) + }) + } else { + return false + } + }) + } + } +} +</script> + +<style scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/email/index.vue b/UI source code/dns_mapping_ui-master/src/views/tools/email/index.vue new file mode 100644 index 0000000..d0e6387 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/email/index.vue @@ -0,0 +1,41 @@ +<template> + <el-tabs v-model="activeName" style="padding-left: 8px;"> + <el-tab-pane label="邮箱配置" name="first"> + <Config /> + </el-tab-pane> + <el-tab-pane label="发送邮件" name="second"> + <Send /> + </el-tab-pane> + <el-tab-pane label="使用说明" name="third"> + <div> + <blockquote class="my-blockquote"> 邮件服务器配置</blockquote> + <pre class="my-code"> + # 邮件服务器的SMTP地址,可选,默认为smtp + # 邮件服务器的SMTP端口,可选,默认465或者25 + # 发件人(必须正确,否则发送失败) + # 用户名,默认为发件人邮箱前缀 + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,如QQ和163等等) + # 是否开启ssl,默认开启</pre> + <blockquote class="my-blockquote">更多帮助</blockquote> + <pre class="my-code">更多帮助请查看文档:<a style="color:#009688" href="http://hutool.mydoc.io/#text_319499" target="_black">hutool工具包</a></pre> + </div> + </el-tab-pane> + </el-tabs> +</template> + +<script> +import Config from './config' +import Send from './send' +export default { + name: 'Email', + components: { Config, Send }, + data() { + return { + activeName: 'second' + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/email/send.vue b/UI source code/dns_mapping_ui-master/src/views/tools/email/send.vue new file mode 100644 index 0000000..d4bd568 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/email/send.vue @@ -0,0 +1,98 @@ +<template> + <div> + <el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="100px"> + <el-form-item label="邮件标题" prop="subject"> + <el-input v-model="form.subject" style="width: 646px" placeholder="请输入邮件标题,标题不能为空" /> + </el-form-item> + <el-form-item label="收件地址" prop="tos"> + <el-input v-model="form.tos" style="width: 646px" placeholder="请输入收件地址,多个地址英文逗号,隔开" /> + </el-form-item> + <div ref="editor" class="editor" /> + <el-button :loading="loading" style="margin-left:1.6%;margin-bottom: 30px" size="medium" type="primary" @click="doSubmit">发送邮件</el-button> + </el-form> + </div> +</template> + +<script> +import { send } from '@/api/tools/email' +import { upload } from '@/utils/upload' +import { mapGetters } from 'vuex' +import E from 'wangeditor' +export default { + name: 'Index', + data() { + return { + loading: false, form: { subject: '', tos: '', content: '' }, + rules: { + subject: [ + { required: true, message: '标题不能为空', trigger: 'blur' } + ], + tos: [ + { required: true, message: '收件人不能为空', trigger: 'blur' } + ] + } + } + }, + computed: { + ...mapGetters([ + 'imagesUploadApi', + 'baseApi' + ]) + }, + mounted() { + const _this = this + var editor = new E(this.$refs.editor) + // 自定义菜单配置 + editor.config.zIndex = 10 + // 文件上传 + editor.config.customUploadImg = function(files, insert) { + // files 是 input 中选中的文件列表 + // insert 是获取图片 url 后,插入到编辑器的方法 + files.forEach(image => { + upload(_this.imagesUploadApi, image).then(res => { + const data = res.data + const url = _this.baseApi + '/file/' + data.type + '/' + data.realName + insert(url) + }) + }) + } + editor.config.onchange = (html) => { + this.form.content = html + } + editor.create() + }, + methods: { + doSubmit() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.loading = true + send(this.form).then(res => { + this.$notify({ + title: '发送成功', + type: 'success', + duration: 2500 + }) + this.loading = false + }).catch(err => { + this.loading = false + console.log(err.response.data.message) + }) + } else { + return false + } + }) + } + } +} +</script> + +<style scoped> + .editor{ + text-align:left; + margin: 20px; + width: 730px; + } + ::v-deep .w-e-text-container { + height: 360px !important; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/storage/index.vue b/UI source code/dns_mapping_ui-master/src/views/tools/storage/index.vue new file mode 100644 index 0000000..5bb3fc0 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/storage/index.vue @@ -0,0 +1,36 @@ +<template> + <el-tabs v-model="activeName" style="padding-left: 8px;" @tab-click="tabClick"> + <el-tab-pane label="本地存储" name="first"> + <Local ref="local" /> + </el-tab-pane> + <el-tab-pane label="七牛云存储" name="second"> + <QiNiu ref="qiNiu" /> + </el-tab-pane> + </el-tabs> +</template> + +<script> +import QiNiu from './qiniu/index' +import Local from './local/index' +export default { + name: 'Storage', + components: { QiNiu, Local }, + data() { + return { + activeName: 'first' + } + }, + methods: { + tabClick(name) { + if (this.activeName === 'first') { + this.$refs.local.crud.toQuery() + } else { + this.$refs.qiNiu.crud.toQuery() + } + } + } +} +</script> + +<style scoped> +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/storage/local/index.vue b/UI source code/dns_mapping_ui-master/src/views/tools/storage/local/index.vue new file mode 100644 index 0000000..3adf8a0 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/storage/local/index.vue @@ -0,0 +1,184 @@ +<template> + <div class="app-container" style="padding: 8px;"> + <!--工具栏--> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.blurry" clearable size="small" placeholder="输入内容模糊搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <rrOperation /> + </div> + <crudOperation :permission="permission"> + <!-- 新增 --> + <el-button + slot="left" + v-permission="['admin','storage:add']" + class="filter-item" + size="mini" + type="primary" + icon="el-icon-upload" + @click="crud.toAdd" + >上传 + </el-button> + </crudOperation> + </div> + <!--表单组件--> + <el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.add ? '文件上传' : '编辑文件'" width="500px"> + <el-form ref="form" :model="form" size="small" label-width="80px"> + <el-form-item label="文件名"> + <el-input v-model="form.name" style="width: 370px;" /> + </el-form-item> + <!-- 上传文件 --> + <el-form-item v-if="crud.status.add" label="上传"> + <el-upload + ref="upload" + :limit="1" + :before-upload="beforeUpload" + :auto-upload="false" + :headers="headers" + :on-success="handleSuccess" + :on-error="handleError" + :action="fileUploadApi + '?name=' + form.name" + > + <div class="eladmin-upload"><i class="el-icon-upload" /> 添加文件</div> + <div slot="tip" class="el-upload__tip">可上传任意格式文件,且不超过100M</div> + </el-upload> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="crud.cancelCU">取消</el-button> + <el-button v-if="crud.status.add" :loading="loading" type="primary" @click="upload">确认</el-button> + <el-button v-else :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> + </div> + </el-dialog> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> + <el-table-column type="selection" width="55" /> + <el-table-column prop="name" label="文件名"> + <template slot-scope="scope"> + <el-popover + :content="'file/' + scope.row.type + '/' + scope.row.realName" + placement="top-start" + title="路径" + width="200" + trigger="hover" + > + <a + slot="reference" + :href="baseApi + '/file/' + scope.row.type + '/' + scope.row.realName" + class="el-link--primary" + style="word-break:keep-all;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color: #1890ff;font-size: 13px;" + target="_blank" + > + {{ scope.row.name }} + </a> + </el-popover> + </template> + </el-table-column> + <el-table-column prop="path" label="预览图"> + <template slot-scope="{row}"> + <el-image + :src=" baseApi + '/file/' + row.type + '/' + row.realName" + :preview-src-list="[baseApi + '/file/' + row.type + '/' + row.realName]" + fit="contain" + lazy + class="el-avatar" + > + <div slot="error"> + <i class="el-icon-document" /> + </div> + </el-image> + </template> + </el-table-column> + <el-table-column prop="suffix" label="文件类型" /> + <el-table-column prop="type" label="类别" /> + <el-table-column prop="size" label="大小" /> + <el-table-column prop="operate" label="操作人" /> + <el-table-column prop="createTime" label="创建日期" /> + </el-table> + <!--分页组件--> + <pagination /> + </div> +</template> + +<script> +import { mapGetters } from 'vuex' +import { getToken } from '@/utils/auth' +import crudFile from '@/api/tools/localStorage' +import CRUD, { presenter, header, form, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import pagination from '@crud/Pagination' +import DateRangePicker from '@/components/DateRangePicker' + +const defaultForm = { id: null, name: '' } +export default { + components: { pagination, crudOperation, rrOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '文件', url: 'api/localStorage', crudMethod: { ...crudFile }}) + }, + mixins: [presenter(), header(), form(defaultForm), crud()], + data() { + return { + delAllLoading: false, + loading: false, + headers: { 'Authorization': getToken() }, + permission: { + edit: ['admin', 'storage:edit'], + del: ['admin', 'storage:del'] + } + } + }, + computed: { + ...mapGetters([ + 'baseApi', + 'fileUploadApi' + ]) + }, + created() { + this.crud.optShow.add = false + }, + methods: { + // 上传文件 + upload() { + this.$refs.upload.submit() + }, + beforeUpload(file) { + let isLt2M = true + isLt2M = file.size / 1024 / 1024 < 100 + if (!isLt2M) { + this.loading = false + this.$message.error('上传文件大小不能超过 100MB!') + } + this.form.name = file.name + return isLt2M + }, + handleSuccess(response, file, fileList) { + this.crud.notify('上传成功', CRUD.NOTIFICATION_TYPE.SUCCESS) + this.$refs.upload.clearFiles() + this.crud.status.add = CRUD.STATUS.NORMAL + this.crud.resetForm() + this.crud.toQuery() + }, + // 监听上传失败 + handleError(e, file, fileList) { + const msg = JSON.parse(e.message) + this.$notify({ + title: msg.message, + type: 'error', + duration: 2500 + }) + this.loading = false + } + } +} +</script> + +<style scoped> + ::v-deep .el-image__error, .el-image__placeholder{ + background: none; + } + ::v-deep .el-image-viewer__wrapper{ + top: 55px; + } +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/storage/qiniu/form.vue b/UI source code/dns_mapping_ui-master/src/views/tools/storage/qiniu/form.vue new file mode 100644 index 0000000..c77904e --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/storage/qiniu/form.vue @@ -0,0 +1,98 @@ +<template> + <el-dialog :visible.sync="dialog" :close-on-click-modal="false" title="七牛云配置" append-to-body width="580px"> + <el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="110px"> + <el-form-item label="Access Key" prop="accessKey"> + <el-input v-model="form.accessKey" style="width: 95%" placeholder="accessKey,在安全中心,秘钥管理中查看" /> + </el-form-item> + <el-form-item label="Secret Key" prop="secretKey"> + <el-input v-model="form.secretKey" type="password" style="width: 95%;" placeholder="secretKey,在安全中心,秘钥管理中查看" /> + </el-form-item> + <el-form-item label="空间名称" prop="bucket"> + <el-input v-model="form.bucket" style="width: 95%;" placeholder="存储空间名称作为唯一的 Bucket 识别符" /> + </el-form-item> + <el-form-item label="外链域名" prop="host"> + <el-input v-model="form.host" style="width: 95%;" placeholder="外链域名,可自定义,需在七牛云绑定" /> + </el-form-item> + <el-form-item label="存储区域"> + <el-select v-model="form.zone" placeholder="请选择存储区域"> + <el-option + v-for="item in zones" + :key="item" + :label="item" + :value="item" + /> + </el-select> + </el-form-item> + <el-form-item label="空间类型" prop="type"> + <el-radio v-model="form.type" label="公开">公开</el-radio> + <el-radio v-model="form.type" label="私有">私有</el-radio> + </el-form-item> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="text" @click="dialog = false">取消</el-button> + <el-button :loading="loading" type="primary" @click="doSubmit">确认</el-button> + </div> + </el-dialog> +</template> + +<script> +import { get, update } from '@/api/tools/qiniu' +export default { + data() { + return { + zones: ['华东', '华北', '华南', '北美', '东南亚'], dialog: false, + loading: false, form: { accessKey: '', secretKey: '', bucket: '', host: '', zone: '', type: '' }, + rules: { + accessKey: [ + { required: true, message: '请输入accessKey', trigger: 'blur' } + ], + secretKey: [ + { required: true, message: '请输入secretKey', trigger: 'blur' } + ], + bucket: [ + { required: true, message: '请输入空间名称', trigger: 'blur' } + ], + host: [ + { required: true, message: '请输入外链域名', trigger: 'blur' } + ], + type: [ + { required: true, message: '空间类型不能为空', trigger: 'blur' } + ] + } + } + }, + methods: { + init() { + get().then(res => { + this.form = res + }) + }, + doSubmit() { + this.$refs['form'].validate((valid) => { + if (valid) { + this.loading = true + update(this.form).then(res => { + this.$notify({ + title: '修改成功', + type: 'success', + duration: 2500 + }) + this.$parent.crud.toQuery() + this.loading = false + this.dialog = false + }).catch(err => { + this.loading = false + console.log(err.response.data.message) + }) + } else { + return false + } + }) + } + } +} +</script> + +<style scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/storage/qiniu/index.vue b/UI source code/dns_mapping_ui-master/src/views/tools/storage/qiniu/index.vue new file mode 100644 index 0000000..bdb9c8d --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/storage/qiniu/index.vue @@ -0,0 +1,189 @@ +<template> + <div class="app-container" style="padding: 8px;"> + <!--表单组件--> + <eForm ref="form" /> + <!-- 工具栏 --> + <div class="head-container"> + <div v-if="crud.props.searchToggle"> + <!-- 搜索 --> + <el-input v-model="query.key" clearable size="small" placeholder="输入文件名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" /> + <date-range-picker v-model="query.createTime" class="date-item" /> + <rrOperation /> + </div> + <crudOperation :permission="permission"> + <template slot="left"> + <!-- 上传 --> + <el-button class="filter-item" size="mini" type="primary" icon="el-icon-upload" @click="dialog = true">上传</el-button> + <!-- 同步 --> + <el-button :icon="icon" class="filter-item" size="mini" type="warning" @click="synchronize">同步</el-button> + <!-- 配置 --> + <el-button + class="filter-item" + size="mini" + type="success" + icon="el-icon-s-tools" + @click="doConfig" + >配置</el-button> + </template> + </crudOperation> + <!-- 文件上传 --> + <el-dialog :visible.sync="dialog" :close-on-click-modal="false" append-to-body width="500px" @close="doSubmit"> + <el-upload + :before-remove="handleBeforeRemove" + :on-success="handleSuccess" + :on-error="handleError" + :file-list="fileList" + :headers="headers" + :action="qiNiuUploadApi" + class="upload-demo" + multiple + > + <el-button size="small" type="primary">点击上传</el-button> + <div slot="tip" style="display: block;" class="el-upload__tip">请勿上传违法文件,且文件不超过15M</div> + </el-upload> + <div slot="footer" class="dialog-footer"> + <el-button type="primary" @click="doSubmit">确认</el-button> + </div> + </el-dialog> + <!--表格渲染--> + <el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> + <el-table-column type="selection" width="55" /> + <el-table-column prop="name" :show-overflow-tooltip="true" label="文件名"> + <template slot-scope="scope"> + <a href="JavaScript:" class="el-link el-link--primary" target="_blank" type="primary" @click="download(scope.row.id)">{{ scope.row.key }}</a> + </template> + </el-table-column> + <el-table-column :show-overflow-tooltip="true" prop="suffix" label="文件类型" @selection-change="crud.selectionChangeHandler" /> + <el-table-column prop="bucket" label="空间名称" /> + <el-table-column prop="size" label="文件大小" /> + <el-table-column prop="type" label="空间类型" /> + <el-table-column prop="updateTime" label="创建日期" /> + </el-table> + <!--分页组件--> + <pagination /> + </div> + </div> +</template> + +<script> +import crudQiNiu from '@/api/tools/qiniu' +import { mapGetters } from 'vuex' +import { getToken } from '@/utils/auth' +import eForm from './form' +import CRUD, { presenter, header, crud } from '@crud/crud' +import rrOperation from '@crud/RR.operation' +import crudOperation from '@crud/CRUD.operation' +import pagination from '@crud/Pagination' +import DateRangePicker from '@/components/DateRangePicker' + +export default { + components: { eForm, pagination, crudOperation, rrOperation, DateRangePicker }, + cruds() { + return CRUD({ title: '七牛云文件', url: 'api/qiNiuContent', crudMethod: { ...crudQiNiu }}) + }, + mixins: [presenter(), header(), crud()], + data() { + return { + permission: { + del: ['admin', 'storage:del'] + }, + title: '文件', dialog: false, + icon: 'el-icon-refresh', + url: '', headers: { 'Authorization': getToken() }, + dialogImageUrl: '', dialogVisible: false, fileList: [], files: [], newWin: null + } + }, + computed: { + ...mapGetters([ + 'qiNiuUploadApi' + ]) + }, + watch: { + url(newVal, oldVal) { + if (newVal && this.newWin) { + this.newWin.sessionStorage.clear() + this.newWin.location.href = newVal + // 重定向后把url和newWin重置 + this.url = '' + this.newWin = null + } + } + }, + created() { + this.crud.optShow.add = false + this.crud.optShow.edit = false + }, + methods: { + // 七牛云配置 + doConfig() { + const _this = this.$refs.form + _this.init() + _this.dialog = true + }, + handleSuccess(response, file, fileList) { + const uid = file.uid + const id = response.id + this.files.push({ uid, id }) + }, + handleBeforeRemove(file, fileList) { + for (let i = 0; i < this.files.length; i++) { + if (this.files[i].uid === file.uid) { + crudQiNiu.del([this.files[i].id]).then(res => {}) + return true + } + } + }, + handlePictureCardPreview(file) { + this.dialogImageUrl = file.url + this.dialogVisible = true + }, + // 刷新列表数据 + doSubmit() { + this.fileList = [] + this.dialogVisible = false + this.dialogImageUrl = '' + this.dialog = false + this.crud.toQuery() + }, + // 监听上传失败 + handleError(e, file, fileList) { + const msg = JSON.parse(e.message) + this.crud.notify(msg.message, CRUD.NOTIFICATION_TYPE.ERROR) + }, + // 下载文件 + download(id) { + this.downloadLoading = true + // 先打开一个空的新窗口,再请求 + this.newWin = window.open() + crudQiNiu.download(id).then(res => { + this.downloadLoading = false + this.url = res.url + }).catch(err => { + this.downloadLoading = false + console.log(err.response.data.message) + }) + }, + // 同步数据 + synchronize() { + this.icon = 'el-icon-loading' + crudQiNiu.sync().then(res => { + this.icon = 'el-icon-refresh' + this.$message({ + showClose: true, + message: '数据同步成功', + type: 'success', + duration: 1500 + }) + this.crud.toQuery() + }).catch(err => { + this.icon = 'el-icon-refresh' + console.log(err.response.data.message) + }) + } + } +} +</script> + +<style scoped> + +</style> diff --git a/UI source code/dns_mapping_ui-master/src/views/tools/swagger/index.vue b/UI source code/dns_mapping_ui-master/src/views/tools/swagger/index.vue new file mode 100644 index 0000000..5162cd9 --- /dev/null +++ b/UI source code/dns_mapping_ui-master/src/views/tools/swagger/index.vue @@ -0,0 +1,16 @@ +<template> + <elFrame :src="swaggerApi" /> +</template> +<script> +import { mapGetters } from 'vuex' +import elFrame from '@/components/Iframe/index' +export default { + name: 'Swagger', + components: { elFrame }, + computed: { + ...mapGetters([ + 'swaggerApi' + ]) + } +} +</script> diff --git a/UI source code/dns_mapping_ui-master/vue.config.js b/UI source code/dns_mapping_ui-master/vue.config.js new file mode 100644 index 0000000..371de6b --- /dev/null +++ b/UI source code/dns_mapping_ui-master/vue.config.js @@ -0,0 +1,144 @@ +'use strict' +const path = require('path') +const defaultSettings = require('./src/settings.js') + +function resolve(dir) { + return path.join(__dirname, dir) +} + +const name = defaultSettings.title // 网址标题 +const port = 8013 // 端口配置 + +// All configuration item explanations can be find in https://cli.vuejs.org/config/ +module.exports = { + // hash 模式下可使用 + // publicPath: process.env.NODE_ENV === 'development' ? '/' : './', + publicPath: '/', + outputDir: 'dist', + assetsDir: 'static', + lintOnSave: process.env.NODE_ENV === 'development', + productionSourceMap: false, + devServer: { + port: port, + open: false, + overlay: { + warnings: false, + errors: true + }, + proxy: { + '/api': { + target: process.env.VUE_APP_BASE_API, + changeOrigin: true, + pathRewrite: { + '^/api': 'api' + } + }, + '/auth': { + target: process.env.VUE_APP_BASE_API, + changeOrigin: true, + pathRewrite: { + '^/auth': 'auth' + } + }, + '/dns': { + target: process.env.VUE_APP_BASE_API, + changeOrigin: true, + pathRewrite: { + '^/dns': 'dns' + } + } + } + }, + configureWebpack: { + // provide the app's title in webpack's name field, so that + // it can be accessed in index.html to inject the correct title. + name: name, + resolve: { + alias: { + '@': resolve('src'), + '@crud': resolve('src/components/Crud') + } + } + }, + chainWebpack(config) { + config.plugins.delete('preload') // TODO: need test + config.plugins.delete('prefetch') // TODO: need test + + // set svg-sprite-loader + config.module + .rule('svg') + .exclude.add(resolve('src/assets/icons')) + .end() + config.module + .rule('icons') + .test(/\.svg$/) + .include.add(resolve('src/assets/icons')) + .end() + .use('svg-sprite-loader') + .loader('svg-sprite-loader') + .options({ + symbolId: 'icon-[name]' + }) + .end() + + // set preserveWhitespace + config.module + .rule('vue') + .use('vue-loader') + .loader('vue-loader') + .tap(options => { + options.compilerOptions.preserveWhitespace = true + return options + }) + .end() + + config + // https://webpack.js.org/configuration/devtool/#development + .when(process.env.NODE_ENV === 'development', + config => config.devtool('cheap-source-map') + ) + + config + .when(process.env.NODE_ENV !== 'development', + config => { + config + .plugin('ScriptExtHtmlWebpackPlugin') + .after('html') + .use('script-ext-html-webpack-plugin', [{ + // `runtime` must same as runtimeChunk name. default is `runtime` + inline: /runtime\..*\.js$/ + }]) + .end() + config + .optimization.splitChunks({ + chunks: 'all', + cacheGroups: { + libs: { + name: 'chunk-libs', + test: /[\\/]node_modules[\\/]/, + priority: 10, + chunks: 'initial' // only package third parties that are initially dependent + }, + elementUI: { + name: 'chunk-elementUI', // split elementUI into a single package + priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app + test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm + }, + commons: { + name: 'chunk-commons', + test: resolve('src/components'), // can customize your rules + minChunks: 3, // minimum common number + priority: 5, + reuseExistingChunk: true + } + } + }) + config.optimization.runtimeChunk('single') + } + ) + }, + transpileDependencies: [ + 'vue-echarts', + 'resize-detector' + ] +} |
