commit 3ecbd0957bfefefc808893f78503325fea53a7c3 Author: zhuyiyi <649091362@qq.com> Date: Mon Jul 13 08:57:05 2026 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ef0de04 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +.git +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + 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: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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 [yyyy] [name of copyright owner] + + 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/README.md b/README.md new file mode 100644 index 0000000..adce168 --- /dev/null +++ b/README.md @@ -0,0 +1,138 @@ +

+ logo +

+ +

ExciteCMS-Layui

+ +

基于Spring Boot 2 + Layui 开发的内容管理系统 / 快速开发脚手架

+ +

+ + + + + + + + + + + + +

+ +## 1、主要功能简介 + ++ 用户管理:基本的增删改查与授权角色; ++ 角色管理:基本的增删改查与授权用户和授权菜单; ++ 菜单管理:基本的增删改查,其中以树状展示; ++ 日志管理:即操作日志管理、登录日志管理等功能; ++ 监控管理:即服务器监控、数据库监控等功能; ++ 开发功能:即代码生成等功能; ++ 第三方功能:如微信支付、支付宝支付、七牛云OSS等功能; ++ + +## 2、视频演示 + +详情请访问:[https://www.bilibili.com/video/BV1Wq4y1h78B](https://www.bilibili.com/video/BV1Wq4y1h78B) + +## 3、主要功能演示 + +> **系统功能**:主要实现了基本的RBAC,即用户管理、权限控制、日志管理、代码生成与系统监控等功能。其预览图如下所示。 + + + + + + + + + + + + + + + + + + +
+ +
首页
+
+ +
用户管理
+
+ +
角色管理
+
+ +
菜单/权限管理
+
+ +
操作日志
+
+ +
登录日志
+
+ +
代码生成
+
+ +
服务器监控
+
+ +> **集成功能**:主要实现了部分第三方组件功能,如支付宝、微信等支付功能,对象存储服务功能,短信服务功能等。其预览见演示视频。 + +## 4、主要技术栈 + +**后的技术栈:** + +| 技术栈 | 说明 | +| :---------------- | :----------------------- | +| Spring Boot 2.5.X | Spring框架 | +| Sa-Token | 权限认证框架 | +| thymeleaf | 前端模板引擎 | +| nekohtml | 提供非严格HTML模式支持 | +| mybatis-plus | Mybatis 的增强工具 | +| freemarker | 代码生成器模板 | +| lombok | Lombok,Java开发工具 | +| druid | 数据库连接池 | +| openapi | 接口文档 | +| fastjson | 阿里巴巴的开源JSON解析库 | + +**前端模板:** + ++ Layui ++ miniLayui + +## 5、开发文档 + +网址1:[https://excitecms.gitee.io](https://shensong.gitee.io) + +网址2:[https://excite.zxdmy.com](https://excite.zxdmy.com) + +> 以上两个开发文档网址内容一致,区别是部署的仓库不同(Gitee和GitHub)。 + +## 6、在线体验 + +网址:[http://demo.excite.zxdmy.com](http://demo.excite.zxdmy.com) + +体验账号:demo@zxdmy.com + +登录密码:123456 + +> 注:① 体验账号只有浏览权限,无增删改的权限。② 由于部分页面设置了固定的长宽,使用电脑浏览器访问体验更佳! + +## 7、支持 + +如果你觉得 ExciteCMS 还不错,可以通过点亮仓库右上角的 Star 来支持我们~ + +## 8、贡献 + +发现BUG?发现功能错误?欢迎提交**issues**:[Gitee](https://gitee.com/ExciteTeam/ExciteCMS-SpringBoot-Layui/issues) | [GitHub](https://github.com/cxh1231/ExciteCMS-SpringBoot-Layui/issues) + +## 9、开源协议 + +[Apache License 2.0](https://gitee.com/ExciteTeam/ExciteCMS-SpringBoot-Layui/blob/master/LICENSE) diff --git a/database/db_excite_cms.sql b/database/db_excite_cms.sql new file mode 100644 index 0000000..83865ff --- /dev/null +++ b/database/db_excite_cms.sql @@ -0,0 +1,396 @@ +/* + Navicat Premium Data Transfer + + Source Server : db_excite_cms + Source Server Type : MySQL + Source Server Version : 50734 + Source Host : 1.15.186.61:3306 + Source Schema : db_excite_cms + + Target Server Type : MySQL + Target Server Version : 50734 + File Encoding : 65001 + + Date: 30/01/2022 18:05:09 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for attach_file +-- ---------------------------- +DROP TABLE IF EXISTS `attach_file`; +CREATE TABLE `attach_file` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '文件主键', + `user_id` bigint(20) NULL DEFAULT NULL COMMENT '上传用户id', + `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件名(服务器内存储的)', + `file_source_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件原名(上传前)', + `file_size` int(11) NULL DEFAULT NULL COMMENT '文件大小', + `file_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件路径', + `file_type` tinyint(4) NULL DEFAULT NULL COMMENT '文件类型 1:图片 2:视频 3:文件', + `file_mime_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件类型(mime-type)', + `file_group_id` bigint(20) NULL DEFAULT 0 COMMENT '文件分组id', + `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1431 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '上传文件记录表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of attach_file +-- ---------------------------- + +-- ---------------------------- +-- Table structure for global_config +-- ---------------------------- +DROP TABLE IF EXISTS `global_config`; +CREATE TABLE `global_config` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键,自增', + `conf_service` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '配置信息的服务:如qiniu,aliyun', + `conf_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '配置信息的主键:如qiniu01、aliyunSms01等等', + `conf_value` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '配置信息的JSON值', + `encrypt` tinyint(4) NULL DEFAULT NULL COMMENT '是否加密:1-是 0-否', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '组件配置信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of global_config +-- ---------------------------- +INSERT INTO `global_config` VALUES (2, 'aliyunSms', 'aliyunSms001', '', 0, NULL, '2022-01-03 20:50:41', NULL); +INSERT INTO `global_config` VALUES (6, 'alipay', 'alipay', '666', 1, NULL, '2022-01-12 17:14:01', NULL); + +-- ---------------------------- +-- Table structure for sys_log_login +-- ---------------------------- +DROP TABLE IF EXISTS `sys_log_login`; +CREATE TABLE `sys_log_login` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_id` int(11) NULL DEFAULT NULL COMMENT '登录用户ID', + `user_account` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '登录用户账号', + `ip` varchar(127) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '登录IP', + `user_agent` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '浏览器Agent', + `req_data` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '请求数据', + `res_data` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '返回数据', + `time_cost` int(11) NULL DEFAULT NULL COMMENT '耗时', + `status` tinyint(4) NULL DEFAULT NULL COMMENT '请求状态:0-失败 | 1-成功', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 54 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '登录日志表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_log_login +-- ---------------------------- +INSERT INTO `sys_log_login` VALUES (53, 10000, '10000@zxdmy.com', '60.233.1.102', 'Windows 10 or Windows Server 2016;Chrome 97.0.4692.99', '[\"10000@zxdmy.com\",\"Pr+v96V9jqGTN6rgRUkGMHKjXuRyzrIVs70jtGoJmoRATDsvSTudyPD5/WqWVjs1nq4tmQX3gWYySzygIyEnOZoNWLe06AKhzId1P7Q0la75WUuLNzqbAs24kMGKfS/7SjFqmtwURHrzn0PALXtkUARhzbErcWe1h3YhFfaIm0g=\",\"0\",null]', '{\"msg\":\"登录成功!\",\"code\":200,\"data\":{\"tokenName\":\"com.zxdmy.excite\",\"tokenValue\":\"6cf72af4-eff9-4167-88c9-ad6aed4ca6be\",\"isLogin\":true,\"loginId\":\"10000\",\"loginType\":\"login\",\"tokenTimeout\":259200,\"sessionTimeout\":259200,\"tokenSessionTimeout\":-2,\"tokenActivityTimeout\":7200,\"loginDevice\":\"default-device\",\"tag\":null},\"success\":true}', 58, 1, '2022-01-30 17:43:27', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_log_request +-- ---------------------------- +DROP TABLE IF EXISTS `sys_log_request`; +CREATE TABLE `sys_log_request` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_id` int(11) NULL DEFAULT NULL COMMENT '请求用户ID', + `ip` varchar(127) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求IP', + `user_agent` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '浏览器Agent', + `req_uri` varchar(1023) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求的URI', + `req_method` varchar(31) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求方法:GET | POST | DELETE', + `req_function` varchar(511) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求的函数', + `req_data` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '请求的数据', + `res_data` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '返回的数据', + `time_cost` int(11) NULL DEFAULT NULL COMMENT '耗时', + `status` tinyint(4) NULL DEFAULT NULL COMMENT '请求状态:0-失败 | 1-成功', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = MyISAM AUTO_INCREMENT = 162 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '操作请求日志表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_log_request +-- ---------------------------- +INSERT INTO `sys_log_request` VALUES (161, 10000, '60.233.1.102', 'Windows 10 or Windows Server 2016;Chrome 97.0.4692.99', '/system/role/update', 'POST', 'SysRoleController.updateRole(..)', '[{\"id\":101,\"name\":\"围观角色\",\"permission\":\"visit\",\"remark\":\"演示用户拥有的权限\",\"sort\":50,\"status\":null,\"createTime\":null,\"updateTime\":null,\"deleteTime\":null,\"checkArr\":\"0\",\"parentId\":\"-1\",\"LAY_CHECKED\":false},[1,2,3,6,7,9,12,4,17,18,20,5,28,25,26,35,36,24,32,34,38,39,40,33,41,42]]', '{\"msg\":\"更新角色成功\",\"code\":200,\"success\":true}', 174, 1, '2022-01-30 17:43:50', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '菜单/权限ID', + `name` varchar(63) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单/权限名称', + `icon` varchar(63) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单图标', + `path` varchar(63) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单/权限路由:对于后台控制类定义,示例:system/user/get/{id}', + `permission` varchar(63) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限标识符:对于后台控制类定义。示例:system:user:list', + `component` varchar(63) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '组件路径:对于前端框架定义。示例:system/user/index', + `parent_id` int(11) NULL DEFAULT NULL COMMENT '上级菜单ID', + `type` varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单类型:C - 目录 | M - 菜单 | B - 按钮', + `sort` int(11) NULL DEFAULT NULL COMMENT '排序:数值越大越靠前', + `editable` tinyint(4) NULL DEFAULT NULL COMMENT '可编辑:0-禁止编辑 | 1-可编辑', + `removable` tinyint(4) NULL DEFAULT NULL COMMENT '可删除:0-禁止删除 | 1-可删除', + `status` tinyint(4) NULL DEFAULT NULL COMMENT '角色状态:0-封禁 | 1-正常 | 2-正常且禁止封禁', + `is_delete` tinyint(4) NULL DEFAULT NULL COMMENT '是否删除:0-未删除 | 1-已删除', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 49 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统菜单/权限表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +INSERT INTO `sys_menu` VALUES (1, '系统功能', 'fa fa-gears', '', 'system:system', NULL, -1, 'N', 100, 0, 0, 2, NULL, '2021-09-16 20:10:10', '2021-12-04 18:53:50', NULL); +INSERT INTO `sys_menu` VALUES (2, '系统管理', 'fa fa-cog', '', 'system:index', NULL, 1, 'C', 80, 0, 0, 2, NULL, '2021-09-16 20:10:10', '2021-12-04 18:53:46', NULL); +INSERT INTO `sys_menu` VALUES (3, '系统用户', 'fa fa-user', '/system/user/index', 'system:user:index', NULL, 2, 'M', 75, 1, 0, 1, NULL, '2021-09-16 20:10:10', '2021-12-09 10:48:48', NULL); +INSERT INTO `sys_menu` VALUES (4, '角色管理', 'fa fa-users', '/system/role/index', 'system:role:index', NULL, 2, 'M', 70, 1, 0, 1, NULL, '2021-09-16 20:10:10', '2021-12-02 21:27:29', NULL); +INSERT INTO `sys_menu` VALUES (5, '菜单管理', 'fa fa-th-list', '/system/menu/index', 'system:menu:index', NULL, 2, 'M', 65, 1, 1, 1, NULL, '2021-09-16 20:10:10', '2021-12-02 21:01:06', NULL); +INSERT INTO `sys_menu` VALUES (6, '查询用户列表', 'fa fa fa-mouse-pointer', '/system/user/list/{type}', 'system:user:list', NULL, 3, 'B', 50, 1, 0, 1, NULL, '2021-10-12 20:50:33', '2021-12-04 17:13:17', NULL); +INSERT INTO `sys_menu` VALUES (7, '访问添加用户页面', 'fa fa-address-card', '/system/user/goAdd', 'system:user:goAdd', NULL, 3, 'B', 50, 1, 1, 1, NULL, '2021-09-16 20:10:10', '2021-12-02 21:45:36', NULL); +INSERT INTO `sys_menu` VALUES (8, '添加用户', 'fa fa-500px', '/system/user/add', 'system:user:add', NULL, 3, 'B', 50, 1, 1, 1, NULL, '2021-09-16 20:10:10', '2021-12-02 21:46:11', NULL); +INSERT INTO `sys_menu` VALUES (9, '访问用户编辑页面', 'fa fa-500px', '/system/user/goEdit', 'system:user:goEdit', NULL, 3, 'B', 50, 1, 1, 1, NULL, '2021-09-16 20:10:10', '2021-12-02 21:47:21', NULL); +INSERT INTO `sys_menu` VALUES (10, '更新用户信息', 'fa fa-address-book', '/system/user/update', 'system:user:update', NULL, 3, 'B', 50, 1, 1, 1, NULL, '2021-09-16 20:10:10', '2021-12-04 17:43:00', NULL); +INSERT INTO `sys_menu` VALUES (11, '删除用户', 'fa fa-address-book', '/system/user/delete', 'system:user:delete', NULL, 3, 'B', 50, 1, 1, 1, NULL, '2021-09-16 20:10:10', '2022-01-30 15:21:14', NULL); +INSERT INTO `sys_menu` VALUES (12, '访问分配角色页面', 'fa fa-address-book', '/system/user/role/{id}', 'system:user:role', NULL, 3, 'B', 50, 1, 1, 1, NULL, '2021-09-16 20:10:10', '2021-12-04 17:25:52', NULL); +INSERT INTO `sys_menu` VALUES (13, '分配角色', 'fa fa-address-book', '/system/user/authRole', 'system:user:authRole', NULL, 3, 'B', 50, 1, 0, 1, NULL, '2021-09-16 20:10:10', '2022-01-30 15:22:43', NULL); +INSERT INTO `sys_menu` VALUES (14, '改变用户状态', 'fa fa-address-book', '/system/user/changeStatus/{status}', 'system:user:changeStatus', NULL, 3, 'B', 50, 1, 1, 1, NULL, '2021-09-16 20:10:10', '2022-01-30 15:19:20', NULL); +INSERT INTO `sys_menu` VALUES (16, '重置密码', 'fa fa-compass', '/system/user/resetPassword', 'system:user:resetPassword', NULL, 3, 'B', 50, 1, 1, 1, NULL, '2021-12-02 17:32:40', '2022-01-30 15:23:33', NULL); +INSERT INTO `sys_menu` VALUES (17, '查询用户列表', 'fa fa-address-book', '/system/role/list', 'system:role:list', NULL, 4, 'B', 50, 1, 1, 1, NULL, '2021-12-02 21:20:41', '2021-12-04 19:01:55', NULL); +INSERT INTO `sys_menu` VALUES (18, '访问添加角色页面', 'fa fa-fonticons', '/system/role/goAdd', 'system:role:goAdd', NULL, 4, 'B', 50, 1, 1, 1, NULL, '2021-12-04 19:03:32', NULL, NULL); +INSERT INTO `sys_menu` VALUES (19, '添加角色', 'fa fa-fonticons', '/system/role/add', 'system:role:add', NULL, 4, 'B', 50, 1, 1, 1, NULL, '2021-12-04 19:03:54', NULL, NULL); +INSERT INTO `sys_menu` VALUES (20, '访问修改角色页面', 'fa fa-fonticons', '/system/role/goEdit/{id}', 'system:role:goEdit', NULL, 4, 'B', 50, 1, 1, 1, NULL, '2021-12-04 19:04:10', '2021-12-04 21:09:28', NULL); +INSERT INTO `sys_menu` VALUES (21, '修改角色', 'fa fa-fonticons', '/system/role/update', 'system:role:update', NULL, 4, 'B', 50, 1, 1, 1, NULL, '2021-12-04 19:04:35', NULL, NULL); +INSERT INTO `sys_menu` VALUES (22, '删除角色', 'fa fa-fonticons', '/system/role/delete', 'system:role:delete', NULL, 4, 'B', 50, 1, 1, 1, NULL, '2021-12-04 21:21:13', '2021-12-04 21:21:23', NULL); +INSERT INTO `sys_menu` VALUES (23, '改变角色状态', 'fa fa-fonticons', '/system/role/changeStatus/{status}', 'system:role:changeStatus', NULL, 4, 'B', 50, 1, 1, 1, NULL, '2021-12-04 21:35:37', '2021-12-08 20:33:05', NULL); +INSERT INTO `sys_menu` VALUES (24, '日志管理', 'fa fa-history', '', 'system:log', NULL, 1, 'C', 50, 1, 1, 1, NULL, '2021-12-06 15:48:11', '2021-12-26 16:30:38', NULL); +INSERT INTO `sys_menu` VALUES (25, '查询菜单列表', 'fa fa-fonticons', '/system/menu/list/{type}', 'system:menu:list', NULL, 5, 'B', 50, 1, 1, 1, NULL, '2021-12-07 11:31:13', NULL, NULL); +INSERT INTO `sys_menu` VALUES (26, '访问添加菜单页面', 'fa fa-fonticons', '/system/menu/goAdd', 'system:menu:goAdd', NULL, 5, 'B', 50, 1, 1, 1, NULL, '2021-12-07 11:31:42', NULL, NULL); +INSERT INTO `sys_menu` VALUES (27, '添加菜单', 'fa fa-fonticons', '/system/menu/add', 'system:menu:add', NULL, 5, 'B', 50, 1, 1, 1, NULL, '2021-12-07 11:31:52', NULL, NULL); +INSERT INTO `sys_menu` VALUES (28, '访问编辑菜单页面', 'fa fa-fonticons', '/system/menu/goEdit/{id}', 'system:menu:goEdit', NULL, 5, 'B', 50, 1, 1, 1, NULL, '2021-12-07 11:34:04', '2021-12-07 20:41:21', NULL); +INSERT INTO `sys_menu` VALUES (29, '编辑菜单', 'fa fa-fonticons', '/system/menu/update', 'system:menu:update', NULL, 5, 'B', 50, 1, 1, 1, NULL, '2021-12-07 11:34:11', '2021-12-07 19:46:47', NULL); +INSERT INTO `sys_menu` VALUES (30, '修改菜单状态', 'fa fa-fonticons', '/system/menu/changeStatus/{status}', 'system:menu:changeStatus', NULL, 5, 'B', 50, 1, 1, 2, NULL, '2021-12-07 11:34:35', '2022-01-30 16:41:24', NULL); +INSERT INTO `sys_menu` VALUES (31, '删除菜单', 'fa fa-fonticons', '/system/menu/remove', 'system:menu:remove', NULL, 5, 'B', 50, 1, 1, 1, NULL, '2021-12-07 11:34:46', '2022-01-30 17:29:12', NULL); +INSERT INTO `sys_menu` VALUES (32, '操作日志', 'fa fa-sliders', '/system/log/request', 'system:log:request', NULL, 24, 'M', 50, 1, 1, 1, NULL, '2021-12-13 19:07:47', '2021-12-26 16:31:38', NULL); +INSERT INTO `sys_menu` VALUES (33, '第三方组件', 'fa fa-fonticons', '', 'component', NULL, -1, 'N', 50, 1, 1, 1, NULL, '2021-12-23 18:23:07', '2022-01-11 20:46:52', NULL); +INSERT INTO `sys_menu` VALUES (34, '登录日志', 'fa fa-street-view', '/system/log/login', 'system:log:login', NULL, 24, 'M', 50, 1, 1, 1, NULL, '2021-12-26 16:27:13', '2021-12-28 20:21:06', NULL); +INSERT INTO `sys_menu` VALUES (35, '开发管理', 'fa fa-gears', '', 'controller:develop', NULL, 1, 'C', 50, 1, 1, 1, NULL, '2021-12-26 16:28:55', '2021-12-26 16:35:59', NULL); +INSERT INTO `sys_menu` VALUES (36, '代码生成', 'fa fa-file-code-o', '/system/develop/generator', 'system:develop:generator', NULL, 35, 'M', 50, 1, 1, 1, NULL, '2021-12-26 16:37:46', '2021-12-26 16:39:26', NULL); +INSERT INTO `sys_menu` VALUES (37, '接口文档', 'fa fa-external-link-square', '/swagger', 'swagger', NULL, 35, 'M', 50, 1, 1, 1, NULL, '2021-12-26 16:39:13', '2022-01-03 14:00:48', NULL); +INSERT INTO `sys_menu` VALUES (38, '系统监控', 'fa fa-dashboard', '', 'controller:monitor', NULL, 1, 'C', 25, 1, 1, 1, NULL, '2021-12-26 16:52:26', '2021-12-26 16:55:27', NULL); +INSERT INTO `sys_menu` VALUES (39, '服务器监控', 'fa fa-line-chart', '/system/monitor/server', 'system:monitor:server', NULL, 38, 'M', 50, 1, 1, 1, NULL, '2021-12-26 16:54:23', '2022-01-30 17:29:18', NULL); +INSERT INTO `sys_menu` VALUES (40, '数据库监控', 'fa fa-database', '/druid/login.html', 'druid:login.html', NULL, 38, 'M', 50, 1, 1, 1, NULL, '2021-12-26 16:54:47', '2022-01-23 21:24:32', NULL); +INSERT INTO `sys_menu` VALUES (41, '微信支付演示', 'fa fa-wechat', '/component/wechatPay/index', 'component:wechatPay:index', NULL, 33, 'M', 50, 1, 1, 1, NULL, '2022-01-11 20:45:02', '2022-01-12 20:01:22', NULL); +INSERT INTO `sys_menu` VALUES (42, '支付宝支付演示', 'fa fa-cc-paypal', '/component/alipay/index', 'component:alipay:index', NULL, 33, 'M', 50, 1, 1, 1, NULL, '2022-01-11 22:57:18', '2022-01-24 21:36:19', NULL); +INSERT INTO `sys_menu` VALUES (43, '阿里云短信服务', 'fa fa-commenting-o', '/component/aliyunSms/index', 'component:aliyunSms:index', NULL, 33, 'M', 50, 1, 1, 1, NULL, '2022-01-12 16:31:08', '2022-01-24 21:35:56', NULL); +INSERT INTO `sys_menu` VALUES (44, '七牛云文件存储', 'fa fa-file', '/component/qiniuOss/index', 'component:qiniuOss:index', NULL, 33, 'M', 50, 1, 1, 1, NULL, '2022-01-24 21:38:10', '2022-01-24 21:53:54', NULL); +INSERT INTO `sys_menu` VALUES (45, '给用户授权/撤销授权', 'fa fa-fonticons', '/system/role/authUser/{type}', 'system:role:authUser', NULL, 4, 'B', 50, 1, 1, 1, NULL, '2022-01-30 16:36:10', '2022-01-30 16:37:46', NULL); +INSERT INTO `sys_menu` VALUES (46, '删除日志', 'fa fa-fonticons', '/system/log/request/delete', 'system:log:request:delete', NULL, 32, 'B', 0, 1, 1, 1, NULL, '2022-01-30 16:39:00', '2022-01-30 16:53:30', NULL); +INSERT INTO `sys_menu` VALUES (47, '生成指定表的代码', 'fa fa-fonticons', '/system/develop/generator/create', 'system:develop:generator:create', NULL, 36, 'B', 50, 1, 1, 1, NULL, '2022-01-30 16:51:03', NULL, NULL); +INSERT INTO `sys_menu` VALUES (48, '删除日志', 'fa fa-fonticons', '/system/log/login/delete', 'system:log:login:delete', NULL, 34, 'B', 50, 1, 1, 1, NULL, '2022-01-30 16:54:05', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色ID', + `name` varchar(63) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名称', + `permission` varchar(63) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色权限标识符,如:admin、guest', + `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` int(11) NULL DEFAULT NULL COMMENT '排序:数值越大越靠前', + `status` tinyint(4) NULL DEFAULT NULL COMMENT '角色状态:0-封禁 | 1-正常 | 2-正常且禁止封禁', + `is_delete` tinyint(4) NULL DEFAULT NULL COMMENT '是否删除:0-未删除 | 1-已删除', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 106 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统角色表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (100, '超级管理员', 'admin', '超级管理员,禁止禁用和删除!', 100, 2, 0, NULL, '2022-01-30 17:15:50', NULL); +INSERT INTO `sys_role` VALUES (101, '围观角色', 'visit', '演示用户拥有的权限', 50, 1, 0, '2021-09-23 19:36:08', '2022-01-30 17:43:50', NULL); +INSERT INTO `sys_role` VALUES (102, 'test2', 'test2', '', 50, 1, 0, NULL, '2022-01-30 16:47:12', NULL); +INSERT INTO `sys_role` VALUES (103, '系统管理员', 'system', '', 50, 0, 0, '2021-12-04 20:55:13', '2021-12-06 20:23:26', NULL); +INSERT INTO `sys_role` VALUES (104, '系统管理员', 'system', '', 50, 0, 0, '2021-12-04 20:56:45', '2021-12-06 20:19:40', NULL); +INSERT INTO `sys_role` VALUES (105, '测试', '1111', '', 50, 0, 0, '2021-12-08 20:55:59', NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu`; +CREATE TABLE `sys_role_menu` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色菜单关联ID', + `role_id` int(11) NOT NULL COMMENT '角色ID', + `menu_id` int(11) NOT NULL COMMENT '菜单/权限ID', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 844 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统角色和菜单/权限关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role_menu +-- ---------------------------- +INSERT INTO `sys_role_menu` VALUES (89, 104, 24); +INSERT INTO `sys_role_menu` VALUES (90, 103, 1); +INSERT INTO `sys_role_menu` VALUES (91, 103, 2); +INSERT INTO `sys_role_menu` VALUES (92, 103, 4); +INSERT INTO `sys_role_menu` VALUES (93, 103, 17); +INSERT INTO `sys_role_menu` VALUES (94, 103, 18); +INSERT INTO `sys_role_menu` VALUES (95, 103, 19); +INSERT INTO `sys_role_menu` VALUES (96, 103, 20); +INSERT INTO `sys_role_menu` VALUES (97, 103, 21); +INSERT INTO `sys_role_menu` VALUES (98, 103, 22); +INSERT INTO `sys_role_menu` VALUES (99, 103, 23); +INSERT INTO `sys_role_menu` VALUES (720, 100, 1); +INSERT INTO `sys_role_menu` VALUES (721, 100, 2); +INSERT INTO `sys_role_menu` VALUES (722, 100, 3); +INSERT INTO `sys_role_menu` VALUES (724, 100, 6); +INSERT INTO `sys_role_menu` VALUES (725, 100, 7); +INSERT INTO `sys_role_menu` VALUES (726, 100, 8); +INSERT INTO `sys_role_menu` VALUES (727, 100, 9); +INSERT INTO `sys_role_menu` VALUES (728, 100, 10); +INSERT INTO `sys_role_menu` VALUES (729, 100, 11); +INSERT INTO `sys_role_menu` VALUES (730, 100, 12); +INSERT INTO `sys_role_menu` VALUES (731, 100, 13); +INSERT INTO `sys_role_menu` VALUES (732, 100, 14); +INSERT INTO `sys_role_menu` VALUES (733, 100, 16); +INSERT INTO `sys_role_menu` VALUES (734, 100, 4); +INSERT INTO `sys_role_menu` VALUES (735, 100, 45); +INSERT INTO `sys_role_menu` VALUES (736, 100, 17); +INSERT INTO `sys_role_menu` VALUES (737, 100, 18); +INSERT INTO `sys_role_menu` VALUES (738, 100, 19); +INSERT INTO `sys_role_menu` VALUES (739, 100, 20); +INSERT INTO `sys_role_menu` VALUES (740, 100, 21); +INSERT INTO `sys_role_menu` VALUES (741, 100, 22); +INSERT INTO `sys_role_menu` VALUES (742, 100, 23); +INSERT INTO `sys_role_menu` VALUES (743, 100, 5); +INSERT INTO `sys_role_menu` VALUES (744, 100, 27); +INSERT INTO `sys_role_menu` VALUES (745, 100, 28); +INSERT INTO `sys_role_menu` VALUES (746, 100, 29); +INSERT INTO `sys_role_menu` VALUES (747, 100, 30); +INSERT INTO `sys_role_menu` VALUES (748, 100, 31); +INSERT INTO `sys_role_menu` VALUES (749, 100, 26); +INSERT INTO `sys_role_menu` VALUES (750, 100, 25); +INSERT INTO `sys_role_menu` VALUES (751, 100, 35); +INSERT INTO `sys_role_menu` VALUES (752, 100, 36); +INSERT INTO `sys_role_menu` VALUES (753, 100, 47); +INSERT INTO `sys_role_menu` VALUES (754, 100, 37); +INSERT INTO `sys_role_menu` VALUES (755, 100, 24); +INSERT INTO `sys_role_menu` VALUES (756, 100, 32); +INSERT INTO `sys_role_menu` VALUES (757, 100, 46); +INSERT INTO `sys_role_menu` VALUES (758, 100, 34); +INSERT INTO `sys_role_menu` VALUES (759, 100, 48); +INSERT INTO `sys_role_menu` VALUES (760, 100, 38); +INSERT INTO `sys_role_menu` VALUES (761, 100, 39); +INSERT INTO `sys_role_menu` VALUES (762, 100, 40); +INSERT INTO `sys_role_menu` VALUES (763, 100, 33); +INSERT INTO `sys_role_menu` VALUES (764, 100, 41); +INSERT INTO `sys_role_menu` VALUES (765, 100, 42); +INSERT INTO `sys_role_menu` VALUES (818, 101, 1); +INSERT INTO `sys_role_menu` VALUES (819, 101, 2); +INSERT INTO `sys_role_menu` VALUES (820, 101, 3); +INSERT INTO `sys_role_menu` VALUES (821, 101, 6); +INSERT INTO `sys_role_menu` VALUES (822, 101, 7); +INSERT INTO `sys_role_menu` VALUES (823, 101, 9); +INSERT INTO `sys_role_menu` VALUES (824, 101, 12); +INSERT INTO `sys_role_menu` VALUES (825, 101, 4); +INSERT INTO `sys_role_menu` VALUES (826, 101, 17); +INSERT INTO `sys_role_menu` VALUES (827, 101, 18); +INSERT INTO `sys_role_menu` VALUES (828, 101, 20); +INSERT INTO `sys_role_menu` VALUES (829, 101, 5); +INSERT INTO `sys_role_menu` VALUES (830, 101, 28); +INSERT INTO `sys_role_menu` VALUES (831, 101, 25); +INSERT INTO `sys_role_menu` VALUES (832, 101, 26); +INSERT INTO `sys_role_menu` VALUES (833, 101, 35); +INSERT INTO `sys_role_menu` VALUES (834, 101, 36); +INSERT INTO `sys_role_menu` VALUES (835, 101, 24); +INSERT INTO `sys_role_menu` VALUES (836, 101, 32); +INSERT INTO `sys_role_menu` VALUES (837, 101, 34); +INSERT INTO `sys_role_menu` VALUES (838, 101, 38); +INSERT INTO `sys_role_menu` VALUES (839, 101, 39); +INSERT INTO `sys_role_menu` VALUES (840, 101, 40); +INSERT INTO `sys_role_menu` VALUES (841, 101, 33); +INSERT INTO `sys_role_menu` VALUES (842, 101, 41); +INSERT INTO `sys_role_menu` VALUES (843, 101, 42); + +-- ---------------------------- +-- Table structure for sys_test +-- ---------------------------- +DROP TABLE IF EXISTS `sys_test`; +CREATE TABLE `sys_test` ( + `id` int(11) NOT NULL, + `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `phone` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_test +-- ---------------------------- + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户主键', + `username` varchar(63) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户姓名', + `avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户头像', + `sex` tinyint(4) NULL DEFAULT NULL COMMENT '用户性别(0-未知 | 1-男 | 2-女)', + `email` varchar(127) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户邮箱', + `phone` varchar(31) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户手机号', + `password` varchar(127) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户密码', + `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注信息', + `status` tinyint(4) NULL DEFAULT NULL COMMENT '用户状态', + `login_ip` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '登录IP', + `login_date` datetime NULL DEFAULT NULL COMMENT '登录时间', + `is_delete` tinyint(4) NULL DEFAULT 0 COMMENT '是否删除(0-未删除 | 1-已删除)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 10020 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统用户表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user` VALUES (10000, '张三', NULL, 1, '10000@zxdmy.com', '18811111111', 'e10adc3949ba59abbe56e057f20f883e', '超级管理员', 1, NULL, NULL, 0, NULL, '2021-12-30 15:18:34', NULL); +INSERT INTO `sys_user` VALUES (10006, '李四', NULL, 1, 'demo@zxdmy.com', '18866666666', 'e10adc3949ba59abbe56e057f20f883e', '演示用户', 1, NULL, NULL, 0, NULL, '2022-01-30 15:15:13', NULL); +INSERT INTO `sys_user` VALUES (10007, '用户2', NULL, 1, '10007@zxdmy.com', '18877777777', 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (10008, '用户3', NULL, 1, '10008@zxdmy.com', '18888888888', 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, NULL, '2022-01-30 16:30:59', NULL); +INSERT INTO `sys_user` VALUES (10009, '用户4', NULL, 1, '10009@zxdmy.com', '18899999999', 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, NULL, '2022-01-30 15:23:53', NULL); +INSERT INTO `sys_user` VALUES (10010, '用户5', NULL, 1, '10010@zxdmy.com', '18810101010', 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (10011, '10000@zxdmy.com', NULL, 0, '10011@qq.com', '18811001100', 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, '2021-12-22 21:53:48', '2022-01-30 16:30:33', NULL); +INSERT INTO `sys_user` VALUES (10012, '用户1', NULL, NULL, '10012@zxdmy.com', NULL, 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (10013, '用户2', NULL, NULL, '10013@zxdmy.com', NULL, 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (10014, '用户3', NULL, NULL, '10014@zxdmy.com', NULL, 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, NULL, '2021-12-29 11:04:48', NULL); +INSERT INTO `sys_user` VALUES (10015, '用户4', NULL, NULL, '10015@zxdmy.com', NULL, 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (10016, '用户5', NULL, NULL, '10016@zxdmy.com', NULL, 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (10017, '张三', NULL, NULL, '10017@zxdmy.com', NULL, 'e10adc3949ba59abbe56e057f20f883e', NULL, 0, NULL, NULL, 0, NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (10018, '王二麻子', NULL, 1, 'hahah@zxdmy.com', '18811001122', 'e10adc3949ba59abbe56e057f20f883e', '', 0, NULL, NULL, 0, '2021-12-29 10:09:43', '2021-12-29 11:05:31', NULL); +INSERT INTO `sys_user` VALUES (10019, '哈哈哈', NULL, 0, 'hahaaaa@zxdmy.com', '18811001111', 'e10adc3949ba59abbe56e057f20f883e', '', 0, NULL, NULL, 0, '2021-12-29 10:12:55', '2021-12-29 10:36:17', NULL); + +-- ---------------------------- +-- Table structure for sys_user_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role`; +CREATE TABLE `sys_user_role` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户角色关联ID', + `user_id` int(11) NOT NULL COMMENT '用户ID', + `role_id` int(11) NOT NULL COMMENT '角色ID', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统用户和角色关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_role +-- ---------------------------- +INSERT INTO `sys_user_role` VALUES (1, 10000, 100); +INSERT INTO `sys_user_role` VALUES (2, 10000, 101); +INSERT INTO `sys_user_role` VALUES (4, 10006, 101); +INSERT INTO `sys_user_role` VALUES (7, 10018, 101); +INSERT INTO `sys_user_role` VALUES (9, 10011, 101); +INSERT INTO `sys_user_role` VALUES (10, 10006, 102); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/directoryList.md b/directoryList.md new file mode 100644 index 0000000..3781817 --- /dev/null +++ b/directoryList.md @@ -0,0 +1,904 @@ +|-- undefined + |-- .gitignore + |-- LICENSE + |-- pom.xml + |-- README.md + |-- .idea + | |-- .gitignore + | |-- compiler.xml + | |-- encodings.xml + | |-- jarRepositories.xml + | |-- misc.xml + | |-- runConfigurations.xml + | |-- uiDesigner.xml + | |-- vcs.xml + | |-- workspace.xml + | |-- artifacts + | | |-- shensong_jar.xml + | |-- inspectionProfiles + | |-- Project_Default.xml + |-- database + | |-- db_excite_cms(Only struct).sql + | |-- db_excite_cms(Struct and data).sql + |-- ss-admin + | |-- pom.xml + | |-- README.md + | |-- src + | | |-- main + | | | |-- java + | | | | |-- com + | | | | |-- zxdmy + | | | | |-- excite + | | | | |-- admin + | | | | |-- ExciteAdminApplication.java + | | | | |-- controller + | | | | |-- advanced + | | | | | |-- GeneratorController.java + | | | | | |-- MonitorController.java + | | | | |-- component + | | | | | |-- AlipayController.java + | | | | | |-- QiniuOssController.java + | | | | | |-- WeChatPayController.java + | | | | |-- system + | | | | | |-- SysController.java + | | | | | |-- SysLogController.java + | | | | | |-- SysMenuController.java + | | | | | |-- SysRoleController.java + | | | | | |-- SysUserController.java + | | | | |-- tool + | | | | |-- CaptchaController.java + | | | |-- resources + | | | |-- application.yml + | | | |-- banner.txt + | | | |-- static + | | | | |-- api + | | | | | |-- clear.json + | | | | | |-- init.json + | | | | | |-- menus.json + | | | | | |-- table.json + | | | | | |-- tableSelect.json + | | | | | |-- upload.json + | | | | |-- css + | | | | | |-- layuimini.css + | | | | | |-- login.css + | | | | | |-- public.css + | | | | | |-- login2 + | | | | | | |-- admin.css + | | | | | | |-- login2.css + | | | | | |-- themes + | | | | | |-- default.css + | | | | |-- doc + | | | | | |-- AllInOne.css + | | | | | |-- font.css + | | | | | |-- highlight.min.js + | | | | | |-- index.html + | | | | | |-- jquery.min.js + | | | | | |-- xt256.min.css + | | | | |-- images + | | | | | |-- bg-login.jpg + | | | | | |-- bg.jpg + | | | | | |-- captcha.jpg + | | | | | |-- donate_qrcode.png + | | | | | |-- favicon.ico + | | | | | |-- favicon2.ico + | | | | | |-- home.png + | | | | | |-- icon-login.png + | | | | | |-- ic_404.png + | | | | | |-- loginbg.png + | | | | | |-- logo.png + | | | | | |-- logo2.png + | | | | |-- js + | | | | | |-- lay-config.js + | | | | | |-- time.js + | | | | | |-- lay-module + | | | | | |-- dtree + | | | | | | |-- dtree.css + | | | | | | |-- dtree.js + | | | | | | |-- 开发者日志.txt + | | | | | | |-- font + | | | | | | |-- dtreefont.css + | | | | | | |-- dtreefont.eot + | | | | | | |-- dtreefont.svg + | | | | | | |-- dtreefont.ttf + | | | | | | |-- dtreefont.woff + | | | | | | |-- icons.json + | | | | | |-- echarts + | | | | | | |-- echarts.js + | | | | | | |-- echartsTheme.js + | | | | | |-- iconPicker + | | | | | | |-- iconPickerFa.js + | | | | | |-- layarea + | | | | | | |-- layarea.js + | | | | | |-- layuimini + | | | | | | |-- miniAdmin.js + | | | | | | |-- miniMenu.js + | | | | | | |-- miniTab.js + | | | | | | |-- miniTheme.js + | | | | | | |-- miniTongji.js + | | | | | |-- step-lay + | | | | | | |-- step.css + | | | | | | |-- step.js + | | | | | |-- tableSelect + | | | | | | |-- tableSelect.js + | | | | | |-- treetable-lay + | | | | | | |-- treetable.css + | | | | | | |-- treetable.js + | | | | | |-- treetable-lay-3.x + | | | | | | |-- treeTable.css + | | | | | | |-- treeTable.js + | | | | | | |-- treeTable2.js + | | | | | |-- wangEditor + | | | | | |-- wangEditor.css + | | | | | |-- wangEditor.js + | | | | | |-- wangEditor.min.css + | | | | | |-- wangEditor.min.js + | | | | | |-- wangEditor.min.js.map + | | | | | |-- fonts + | | | | | |-- w-e-icon.woff + | | | | |-- lib + | | | | |-- font-awesome-4.7.0 + | | | | | |-- HELP-US-OUT.txt + | | | | | |-- css + | | | | | | |-- font-awesome.css + | | | | | | |-- font-awesome.min.css + | | | | | |-- fonts + | | | | | | |-- fontawesome-webfont.eot + | | | | | | |-- fontawesome-webfont.svg + | | | | | | |-- fontawesome-webfont.ttf + | | | | | | |-- fontawesome-webfont.woff + | | | | | | |-- fontawesome-webfont.woff2 + | | | | | | |-- FontAwesome.otf + | | | | | |-- less + | | | | | | |-- animated.less + | | | | | | |-- bordered-pulled.less + | | | | | | |-- core.less + | | | | | | |-- fixed-width.less + | | | | | | |-- font-awesome.less + | | | | | | |-- icons.less + | | | | | | |-- larger.less + | | | | | | |-- list.less + | | | | | | |-- mixins.less + | | | | | | |-- path.less + | | | | | | |-- rotated-flipped.less + | | | | | | |-- screen-reader.less + | | | | | | |-- stacked.less + | | | | | | |-- variables.less + | | | | | |-- scss + | | | | | |-- font-awesome.scss + | | | | | |-- _animated.scss + | | | | | |-- _bordered-pulled.scss + | | | | | |-- _core.scss + | | | | | |-- _fixed-width.scss + | | | | | |-- _icons.scss + | | | | | |-- _larger.scss + | | | | | |-- _list.scss + | | | | | |-- _mixins.scss + | | | | | |-- _path.scss + | | | | | |-- _rotated-flipped.scss + | | | | | |-- _screen-reader.scss + | | | | | |-- _stacked.scss + | | | | | |-- _variables.scss + | | | | |-- highlight + | | | | | |-- highlight.min.css + | | | | | |-- highlight.min.js + | | | | |-- jq-module + | | | | | |-- jquery.particleground.min.js + | | | | | |-- paigusu.min.js + | | | | | |-- zyupload + | | | | | |-- zyupload-1.0.0.min.css + | | | | | |-- zyupload-1.0.0.min.js + | | | | |-- jquery-3.4.1 + | | | | | |-- jquery-3.4.1.min.js + | | | | |-- jsencrypt + | | | | | |-- jsencrypt.min.js + | | | | | |-- rsa.js + | | | | |-- layui-v2.6.3 + | | | | | |-- layui.js + | | | | | |-- css + | | | | | | |-- layui.css + | | | | | | |-- modules + | | | | | | |-- code.css + | | | | | | |-- laydate + | | | | | | | |-- default + | | | | | | | |-- laydate.css + | | | | | | |-- layer + | | | | | | |-- default + | | | | | | |-- icon-ext.png + | | | | | | |-- icon.png + | | | | | | |-- layer.css + | | | | | | |-- loading-0.gif + | | | | | | |-- loading-1.gif + | | | | | | |-- loading-2.gif + | | | | | |-- font + | | | | | |-- iconfont.eot + | | | | | |-- iconfont.svg + | | | | | |-- iconfont.ttf + | | | | | |-- iconfont.woff + | | | | | |-- iconfont.woff2 + | | | | |-- qrcode + | | | | |-- qrcode.min.js + | | | |-- templates + | | | |-- component + | | | | |-- alipay + | | | | | |-- index.html + | | | | |-- qiniuOss + | | | | | |-- index.html + | | | | |-- wechatPay + | | | | |-- index.html + | | | |-- error + | | | | |-- 404.html + | | | | |-- 500.html + | | | | |-- error.html + | | | |-- system + | | | |-- index.html + | | | |-- login.html + | | | |-- welcome.html + | | | |-- advanced + | | | | |-- generator.html + | | | | |-- monitorServer.html + | | | |-- log + | | | | |-- login.html + | | | | |-- request.html + | | | |-- menu + | | | | |-- add.html + | | | | |-- edit.html + | | | | |-- index.html + | | | |-- role + | | | | |-- add.html + | | | | |-- authUser.html + | | | | |-- edit.html + | | | | |-- index.html + | | | |-- user + | | | | |-- add.html + | | | | |-- authRole.html + | | | | |-- edit.html + | | | | |-- index.html + | | | |-- userCenter + | | | |-- password.html + | | | |-- setting.html + | | |-- test + | | |-- java + | | |-- com + | | |-- zxdmy + | | |-- excite + | | |-- admin + | | |-- CodeGenerator.java + | | |-- ExciteAdminApplicationTests.java + | | |-- SmartDocGenerator.java + | | |-- component + | | | |-- AlipayTest.java + | | | |-- AliyunSmsTest.java + | | | |-- WeChatPayTest.java + | | |-- service + | | | |-- IGlobalConfigServiceTest.java + | | | |-- ISysMenuServiceTest.java + | | | |-- ISysUserServiceTest.java + | | |-- utils + | | |-- RedisUtilsTest.java + | |-- target + | |-- ss-admin-2.0.0.jar + | |-- ss-admin-2.0.0.jar.original + | |-- classes + | | |-- application.yml + | | |-- banner.txt + | | |-- com + | | | |-- zxdmy + | | | |-- excite + | | | |-- admin + | | | |-- ExciteAdminApplication.class + | | | |-- controller + | | | |-- advanced + | | | | |-- GeneratorController$1.class + | | | | |-- GeneratorController$2.class + | | | | |-- GeneratorController.class + | | | | |-- MonitorController.class + | | | |-- component + | | | | |-- AlipayController.class + | | | | |-- QiniuOssController.class + | | | | |-- WeChatPayController.class + | | | |-- system + | | | | |-- SysController.class + | | | | |-- SysLogController.class + | | | | |-- SysMenuController.class + | | | | |-- SysRoleController.class + | | | | |-- SysUserController.class + | | | |-- tool + | | | |-- CaptchaController.class + | | |-- static + | | | |-- api + | | | | |-- clear.json + | | | | |-- init.json + | | | | |-- menus.json + | | | | |-- table.json + | | | | |-- tableSelect.json + | | | | |-- upload.json + | | | |-- css + | | | | |-- layuimini.css + | | | | |-- login.css + | | | | |-- public.css + | | | | |-- login2 + | | | | | |-- admin.css + | | | | | |-- login2.css + | | | | |-- themes + | | | | |-- default.css + | | | |-- doc + | | | | |-- AllInOne.css + | | | | |-- font.css + | | | | |-- highlight.min.js + | | | | |-- index.html + | | | | |-- jquery.min.js + | | | | |-- xt256.min.css + | | | |-- images + | | | | |-- bg-login.jpg + | | | | |-- bg.jpg + | | | | |-- captcha.jpg + | | | | |-- donate_qrcode.png + | | | | |-- favicon.ico + | | | | |-- favicon2.ico + | | | | |-- home.png + | | | | |-- icon-login.png + | | | | |-- ic_404.png + | | | | |-- loginbg.png + | | | | |-- logo.png + | | | | |-- logo2.png + | | | |-- js + | | | | |-- lay-config.js + | | | | |-- time.js + | | | | |-- lay-module + | | | | |-- dtree + | | | | | |-- dtree.css + | | | | | |-- dtree.js + | | | | | |-- 开发者日志.txt + | | | | | |-- font + | | | | | |-- dtreefont.css + | | | | | |-- dtreefont.eot + | | | | | |-- dtreefont.svg + | | | | | |-- dtreefont.ttf + | | | | | |-- dtreefont.woff + | | | | | |-- icons.json + | | | | |-- echarts + | | | | | |-- echarts.js + | | | | | |-- echartsTheme.js + | | | | |-- iconPicker + | | | | | |-- iconPickerFa.js + | | | | |-- layarea + | | | | | |-- layarea.js + | | | | |-- layuimini + | | | | | |-- miniAdmin.js + | | | | | |-- miniMenu.js + | | | | | |-- miniTab.js + | | | | | |-- miniTheme.js + | | | | | |-- miniTongji.js + | | | | |-- step-lay + | | | | | |-- step.css + | | | | | |-- step.js + | | | | |-- tableSelect + | | | | | |-- tableSelect.js + | | | | |-- treetable-lay + | | | | | |-- treetable.css + | | | | | |-- treetable.js + | | | | |-- treetable-lay-3.x + | | | | | |-- treeTable.css + | | | | | |-- treeTable.js + | | | | | |-- treeTable2.js + | | | | |-- wangEditor + | | | | |-- wangEditor.css + | | | | |-- wangEditor.js + | | | | |-- wangEditor.min.css + | | | | |-- wangEditor.min.js + | | | | |-- wangEditor.min.js.map + | | | | |-- fonts + | | | | |-- w-e-icon.woff + | | | |-- lib + | | | |-- font-awesome-4.7.0 + | | | | |-- HELP-US-OUT.txt + | | | | |-- css + | | | | | |-- font-awesome.css + | | | | | |-- font-awesome.min.css + | | | | |-- fonts + | | | | | |-- fontawesome-webfont.eot + | | | | | |-- fontawesome-webfont.svg + | | | | | |-- fontawesome-webfont.ttf + | | | | | |-- fontawesome-webfont.woff + | | | | | |-- fontawesome-webfont.woff2 + | | | | | |-- FontAwesome.otf + | | | | |-- less + | | | | | |-- animated.less + | | | | | |-- bordered-pulled.less + | | | | | |-- core.less + | | | | | |-- fixed-width.less + | | | | | |-- font-awesome.less + | | | | | |-- icons.less + | | | | | |-- larger.less + | | | | | |-- list.less + | | | | | |-- mixins.less + | | | | | |-- path.less + | | | | | |-- rotated-flipped.less + | | | | | |-- screen-reader.less + | | | | | |-- stacked.less + | | | | | |-- variables.less + | | | | |-- scss + | | | | |-- font-awesome.scss + | | | | |-- _animated.scss + | | | | |-- _bordered-pulled.scss + | | | | |-- _core.scss + | | | | |-- _fixed-width.scss + | | | | |-- _icons.scss + | | | | |-- _larger.scss + | | | | |-- _list.scss + | | | | |-- _mixins.scss + | | | | |-- _path.scss + | | | | |-- _rotated-flipped.scss + | | | | |-- _screen-reader.scss + | | | | |-- _stacked.scss + | | | | |-- _variables.scss + | | | |-- highlight + | | | | |-- highlight.min.css + | | | | |-- highlight.min.js + | | | |-- jq-module + | | | | |-- jquery.particleground.min.js + | | | | |-- paigusu.min.js + | | | | |-- zyupload + | | | | |-- zyupload-1.0.0.min.css + | | | | |-- zyupload-1.0.0.min.js + | | | |-- jquery-3.4.1 + | | | | |-- jquery-3.4.1.min.js + | | | |-- jsencrypt + | | | | |-- jsencrypt.min.js + | | | | |-- rsa.js + | | | |-- layui-v2.6.3 + | | | | |-- layui.js + | | | | |-- css + | | | | | |-- layui.css + | | | | | |-- modules + | | | | | |-- code.css + | | | | | |-- laydate + | | | | | | |-- default + | | | | | | |-- laydate.css + | | | | | |-- layer + | | | | | |-- default + | | | | | |-- icon-ext.png + | | | | | |-- icon.png + | | | | | |-- layer.css + | | | | | |-- loading-0.gif + | | | | | |-- loading-1.gif + | | | | | |-- loading-2.gif + | | | | |-- font + | | | | |-- iconfont.eot + | | | | |-- iconfont.svg + | | | | |-- iconfont.ttf + | | | | |-- iconfont.woff + | | | | |-- iconfont.woff2 + | | | |-- qrcode + | | | |-- qrcode.min.js + | | |-- templates + | | |-- component + | | | |-- alipay + | | | | |-- index.html + | | | |-- qiniuOss + | | | | |-- index.html + | | | |-- wechatPay + | | | |-- index.html + | | |-- error + | | | |-- 404.html + | | | |-- 500.html + | | | |-- error.html + | | |-- system + | | |-- index.html + | | |-- login.html + | | |-- welcome.html + | | |-- advanced + | | | |-- generator.html + | | | |-- monitorServer.html + | | |-- log + | | | |-- login.html + | | | |-- request.html + | | |-- menu + | | | |-- add.html + | | | |-- edit.html + | | | |-- index.html + | | |-- role + | | | |-- add.html + | | | |-- authUser.html + | | | |-- edit.html + | | | |-- index.html + | | |-- user + | | | |-- add.html + | | | |-- authRole.html + | | | |-- edit.html + | | | |-- index.html + | | |-- userCenter + | | |-- password.html + | | |-- setting.html + | |-- generated-sources + | | |-- annotations + | |-- generated-test-sources + | | |-- test-annotations + | |-- maven-archiver + | | |-- pom.properties + | |-- maven-status + | | |-- maven-compiler-plugin + | | |-- compile + | | | |-- default-compile + | | | |-- createdFiles.lst + | | | |-- inputFiles.lst + | | |-- testCompile + | | |-- default-testCompile + | | |-- createdFiles.lst + | | |-- inputFiles.lst + | |-- surefire-reports + | | |-- 2021-12-28T19-22-00_971-jvmRun1.dump + | | |-- com.zxdmy.excite.admin.ExciteAdminApplicationTests.txt + | | |-- com.zxdmy.excite.admin.service.ISysMenuServiceTest.txt + | | |-- com.zxdmy.excite.admin.service.ISysUserServiceTest.txt + | | |-- com.zxdmy.excite.admin.utils.RedisUtilsTest.txt + | | |-- TEST-com.zxdmy.excite.admin.ExciteAdminApplicationTests.xml + | | |-- TEST-com.zxdmy.excite.admin.service.ISysMenuServiceTest.xml + | | |-- TEST-com.zxdmy.excite.admin.service.ISysUserServiceTest.xml + | | |-- TEST-com.zxdmy.excite.admin.utils.RedisUtilsTest.xml + | |-- test-classes + | |-- com + | |-- zxdmy + | |-- excite + | |-- admin + | |-- CodeGenerator$1.class + | |-- CodeGenerator$2.class + | |-- CodeGenerator.class + | |-- ExciteAdminApplicationTests.class + | |-- SmartDocGenerator.class + | |-- component + | | |-- AlipayTest.class + | | |-- AliyunSmsTest.class + | | |-- WeChatPayTest.class + | |-- service + | | |-- IGlobalConfigServiceTest.class + | | |-- ISysMenuServiceTest.class + | | |-- ISysUserServiceTest.class + | |-- utils + | |-- RedisUtilsTest.class + |-- ss-common + | |-- pom.xml + | |-- README.md + | |-- src + | | |-- main + | | |-- java + | | | |-- com + | | | |-- zxdmy + | | | |-- excite + | | | |-- common + | | | |-- base + | | | | |-- BaseController.java + | | | | |-- BaseResult.java + | | | | |-- ErrorController.java + | | | |-- config + | | | | |-- ErrorPageConfig.java + | | | | |-- ExciteConfig.java + | | | | |-- KaptchaConfig.java + | | | | |-- MybatisPlusConfig.java + | | | | |-- RedisConfig.java + | | | | |-- SpringDocConfig.java + | | | |-- entity + | | | | |-- CaptchaDomain.java + | | | | |-- GlobalConfig.java + | | | |-- enums + | | | | |-- ReturnCode.java + | | | | |-- SystemCode.java + | | | |-- exception + | | | | |-- GlobalException.java + | | | | |-- ServiceException.java + | | | |-- mapper + | | | | |-- GlobalConfigMapper.java + | | | |-- service + | | | | |-- CaptchaService.java + | | | | |-- IGlobalConfigService.java + | | | | |-- RedisService.java + | | | | |-- impl + | | | | |-- GlobalConfigServiceImpl.java + | | | |-- utils + | | | |-- ArithUtils.java + | | | |-- DateUtils.java + | | | |-- HttpServletRequestUtil.java + | | | |-- KaptchaMathOneTextCreator.java + | | | |-- KaptchaMathTwoTextCreator.java + | | | |-- MyCaptchaUtil.java + | | |-- resources + | | |-- mapper + | | |-- GlobalConfigMapper.xml + | |-- target + | |-- ss-common-2.0.0.jar + | |-- classes + | | |-- com + | | | |-- zxdmy + | | | |-- excite + | | | |-- common + | | | |-- base + | | | | |-- BaseController.class + | | | | |-- BaseResult.class + | | | | |-- ErrorController.class + | | | |-- config + | | | | |-- ErrorPageConfig.class + | | | | |-- ExciteConfig.class + | | | | |-- KaptchaConfig.class + | | | | |-- MybatisPlusConfig.class + | | | | |-- RedisConfig.class + | | | | |-- SpringDocConfig.class + | | | |-- entity + | | | | |-- CaptchaDomain.class + | | | | |-- GlobalConfig.class + | | | |-- enums + | | | | |-- ReturnCode.class + | | | | |-- SystemCode.class + | | | |-- exception + | | | | |-- GlobalException.class + | | | | |-- ServiceException.class + | | | |-- mapper + | | | | |-- GlobalConfigMapper.class + | | | |-- service + | | | | |-- CaptchaService.class + | | | | |-- IGlobalConfigService.class + | | | | |-- RedisService.class + | | | | |-- impl + | | | | |-- GlobalConfigServiceImpl.class + | | | |-- utils + | | | |-- ArithUtils.class + | | | |-- DateUtils.class + | | | |-- HttpServletRequestUtil.class + | | | |-- KaptchaMathOneTextCreator.class + | | | |-- KaptchaMathTwoTextCreator.class + | | | |-- MyCaptchaUtil.class + | | |-- mapper + | | | |-- GlobalConfigMapper.xml + | | |-- META-INF + | | |-- spring-configuration-metadata.json + | |-- generated-sources + | | |-- annotations + | |-- maven-archiver + | | |-- pom.properties + | |-- maven-status + | |-- maven-compiler-plugin + | |-- compile + | |-- default-compile + | |-- createdFiles.lst + | |-- inputFiles.lst + |-- ss-component + | |-- pom.xml + | |-- src + | | |-- main + | | |-- java + | | |-- com + | | |-- zxdmy + | | |-- excite + | | |-- component + | | |-- alipay + | | | |-- AlipayService.java + | | |-- aliyun + | | | |-- AliyunOssService.java + | | | |-- AliyunSmsService.java + | | |-- bo + | | | |-- AlipayBO.java + | | | |-- AliyunOssBO.java + | | | |-- AliyunSmsBO.java + | | | |-- JustAuthBO.java + | | | |-- QiniuOssBO.java + | | | |-- WeChatPayBO.java + | | |-- justauth + | | | |-- JustAuthService.java + | | |-- qiniu + | | | |-- QiniuOssService.java + | | |-- vo + | | | |-- AliyunOssPolicyVO.java + | | | |-- QiniuFileVO.java + | | |-- wechat + | | |-- WeChatPayService.java + | |-- target + | |-- ss-component-2.0.0.jar + | |-- classes + | | |-- com + | | |-- zxdmy + | | |-- excite + | | |-- component + | | |-- alipay + | | | |-- AlipayService.class + | | |-- aliyun + | | | |-- AliyunOssService.class + | | | |-- AliyunSmsService.class + | | |-- bo + | | | |-- AlipayBO.class + | | | |-- AliyunOssBO.class + | | | |-- AliyunSmsBO.class + | | | |-- JustAuthBO.class + | | | |-- QiniuOssBO.class + | | | |-- WeChatPayBO.class + | | |-- justauth + | | | |-- JustAuthService$1.class + | | | |-- JustAuthService.class + | | |-- qiniu + | | | |-- QiniuOssService.class + | | |-- vo + | | | |-- AliyunOssPolicyVO.class + | | | |-- QiniuFileVO.class + | | |-- wechat + | | |-- WeChatPayService.class + | |-- generated-sources + | | |-- annotations + | |-- maven-archiver + | | |-- pom.properties + | |-- maven-status + | |-- maven-compiler-plugin + | |-- compile + | |-- default-compile + | |-- createdFiles.lst + | |-- inputFiles.lst + |-- ss-framework + | |-- pom.xml + | |-- README.md + | |-- src + | | |-- main + | | |-- java + | | |-- com + | | |-- zxdmy + | | |-- excite + | | |-- framework + | | |-- aop + | | | |-- AnnotationSaveLoginLog.java + | | | |-- AnnotationSaveReLog.java + | | | |-- SaveLogAspect.java + | | |-- config + | | |-- oshi + | | | |-- Server.java + | | | |-- domain + | | | |-- Cpu.java + | | | |-- Jvm.java + | | | |-- Mem.java + | | | |-- Sys.java + | | | |-- SysFile.java + | | |-- satoken + | | |-- SaTokenConfig.java + | | |-- SaTokenListenerConfig.java + | | |-- SaTokenStpInterfaceImpl.java + | |-- target + | |-- ss-framework-2.0.0.jar + | |-- classes + | | |-- com + | | |-- zxdmy + | | |-- excite + | | |-- framework + | | |-- aop + | | | |-- AnnotationSaveLoginLog.class + | | | |-- AnnotationSaveReLog.class + | | | |-- SaveLogAspect.class + | | |-- oshi + | | | |-- Server.class + | | | |-- domain + | | | |-- Cpu.class + | | | |-- Jvm.class + | | | |-- Mem.class + | | | |-- Sys.class + | | | |-- SysFile.class + | | |-- satoken + | | |-- SaTokenConfig.class + | | |-- SaTokenListenerConfig.class + | | |-- SaTokenStpInterfaceImpl.class + | |-- generated-sources + | | |-- annotations + | |-- maven-archiver + | | |-- pom.properties + | |-- maven-status + | |-- maven-compiler-plugin + | |-- compile + | |-- default-compile + | |-- createdFiles.lst + | |-- inputFiles.lst + |-- ss-system + |-- pom.xml + |-- README.md + |-- src + | |-- main + | |-- java + | | |-- com + | | |-- zxdmy + | | |-- excite + | | |-- system + | | |-- entity + | | | |-- SysLogLogin.java + | | | |-- SysLogRequest.java + | | | |-- SysMenu.java + | | | |-- SysRole.java + | | | |-- SysRoleMenu.java + | | | |-- SysUser.java + | | | |-- SysUserRole.java + | | |-- mapper + | | | |-- SysLogLoginMapper.java + | | | |-- SysLogRequestMapper.java + | | | |-- SysMenuMapper.java + | | | |-- SysRoleMapper.java + | | | |-- SysRoleMenuMapper.java + | | | |-- SysUserMapper.java + | | | |-- SysUserRoleMapper.java + | | |-- service + | | | |-- ISysLogLoginService.java + | | | |-- ISysLogRequestService.java + | | | |-- ISysMenuService.java + | | | |-- ISysRoleMenuService.java + | | | |-- ISysRoleService.java + | | | |-- ISysUserRoleService.java + | | | |-- ISysUserService.java + | | | |-- impl + | | | |-- SysLogLoginServiceImpl.java + | | | |-- SysLogRequestServiceImpl.java + | | | |-- SysMenuServiceImpl.java + | | | |-- SysRoleMenuServiceImpl.java + | | | |-- SysRoleServiceImpl.java + | | | |-- SysUserRoleServiceImpl.java + | | | |-- SysUserServiceImpl.java + | | |-- utils + | | |-- AuthUtils.java + | |-- resources + | |-- mapper + | |-- SysLogLoginMapper.xml + | |-- SysLogRequestMapper.xml + | |-- SysMenuMapper.xml + | |-- SysRoleMapper.xml + | |-- SysRoleMenuMapper.xml + | |-- SysUserMapper.xml + | |-- SysUserRoleMapper.xml + |-- target + |-- ss-system-2.0.0.jar + |-- classes + | |-- com + | | |-- zxdmy + | | |-- excite + | | |-- system + | | |-- entity + | | | |-- SysLogLogin.class + | | | |-- SysLogRequest.class + | | | |-- SysMenu.class + | | | |-- SysRole.class + | | | |-- SysRoleMenu.class + | | | |-- SysUser.class + | | | |-- SysUserRole.class + | | |-- mapper + | | | |-- SysLogLoginMapper.class + | | | |-- SysLogRequestMapper.class + | | | |-- SysMenuMapper.class + | | | |-- SysRoleMapper.class + | | | |-- SysRoleMenuMapper.class + | | | |-- SysUserMapper.class + | | | |-- SysUserRoleMapper.class + | | |-- service + | | | |-- ISysLogLoginService.class + | | | |-- ISysLogRequestService.class + | | | |-- ISysMenuService.class + | | | |-- ISysRoleMenuService.class + | | | |-- ISysRoleService.class + | | | |-- ISysUserRoleService.class + | | | |-- ISysUserService.class + | | | |-- impl + | | | |-- SysLogLoginServiceImpl.class + | | | |-- SysLogRequestServiceImpl.class + | | | |-- SysMenuServiceImpl.class + | | | |-- SysRoleMenuServiceImpl.class + | | | |-- SysRoleServiceImpl.class + | | | |-- SysUserRoleServiceImpl.class + | | | |-- SysUserServiceImpl$1.class + | | | |-- SysUserServiceImpl.class + | | |-- utils + | | |-- AuthUtils.class + | |-- mapper + | |-- SysLogLoginMapper.xml + | |-- SysLogRequestMapper.xml + | |-- SysMenuMapper.xml + | |-- SysRoleMapper.xml + | |-- SysRoleMenuMapper.xml + | |-- SysUserMapper.xml + | |-- SysUserRoleMapper.xml + |-- generated-sources + | |-- annotations + |-- maven-archiver + | |-- pom.properties + |-- maven-status + |-- maven-compiler-plugin + |-- compile + |-- default-compile + |-- createdFiles.lst + |-- inputFiles.lst diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..1c240ba --- /dev/null +++ b/pom.xml @@ -0,0 +1,198 @@ + + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + + 2.5.4 + + + + com.zxdmy.excite + + shensong + + 2.0.0 + + pom + + Lt-Cloud + + Demo project for Spring Boot + + + + + ss-admin + ss-common + ss-component + ss-system + ss-framework + + + + + + + 2.0.0 + 1.8 + + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + + + + org.springframework.boot + spring-boot-devtools + true + true + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + + org.projectlombok + lombok + true + + + + + com.alibaba + druid-spring-boot-starter + 1.2.8 + + + + mysql + mysql-connector-java + 8.0.28 + runtime + + + + + com.baomidou + mybatis-plus-boot-starter + 3.4.3.2 + + + + + com.baomidou + mybatis-plus-generator + 3.4.1 + + + + + com.alibaba + fastjson + 1.2.83 + + + + + com.fasterxml.jackson.core + jackson-databind + 2.12.7 + + + + + org.springdoc + springdoc-openapi-ui + 1.5.10 + + + + + com.github.shalousun + smart-doc + + test + 2.2.6 + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + cn.dev33 + sa-token-spring-boot-starter + 1.28.0 + + + org.assertj + assertj-core + + + + + + + + + + + cn.hutool + hutool-all + 5.7.12 + + + + com.tennetcn.free + think-swagger-ui-starter + 0.0.5 + + + + + + + + + + + + + + diff --git a/ss-admin/README.md b/ss-admin/README.md new file mode 100644 index 0000000..125cc21 --- /dev/null +++ b/ss-admin/README.md @@ -0,0 +1,3 @@ +# Ss-Admin模块 + +主模块,项目启动的入口,所有控制类模块,配置文件、资源文件等。 diff --git a/ss-admin/pom.xml b/ss-admin/pom.xml new file mode 100644 index 0000000..2682ff6 --- /dev/null +++ b/ss-admin/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + + + com.zxdmy.excite + shensong + 2.0.0 + + + ss-admin + 2.0.0 + ss-admin + + 这里是本模块的描述. + + + + + + + com.zxdmy.excite + ss-framework + 2.0.0 + + + + com.zxdmy.excite + ss-component + 2.0.0 + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + com.zxdmy.excite.admin.ExciteAdminApplication + + + + + + + repackage + + + + + + + + diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/ExciteAdminApplication.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/ExciteAdminApplication.java new file mode 100644 index 0000000..b34b1aa --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/ExciteAdminApplication.java @@ -0,0 +1,30 @@ +package com.zxdmy.excite.admin; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RestController; + +/** + * 项目启动入口 + * + * @author 沈松 + */ +@RestController +@SpringBootApplication(scanBasePackages = { + "com.zxdmy.excite", + "com.zxdmy.excite.system.service", + "com.zxdmy.excite.common.service", +}) +@MapperScan(basePackages = { + "com.zxdmy.excite.system.mapper", + "com.zxdmy.excite.common.mapper", +}) +public class ExciteAdminApplication { + + public static void main(String[] args) { + SpringApplication.run(ExciteAdminApplication.class, args); + System.out.println("系统启动成功,访问 http://localhost:8077 "); + } + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/advanced/GeneratorController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/advanced/GeneratorController.java new file mode 100644 index 0000000..21e07b2 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/advanced/GeneratorController.java @@ -0,0 +1,225 @@ +package com.zxdmy.excite.admin.controller.advanced; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import com.baomidou.mybatisplus.generator.AutoGenerator; +import com.baomidou.mybatisplus.generator.InjectionConfig; +import com.baomidou.mybatisplus.generator.config.*; +import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; +import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import lombok.AllArgsConstructor; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + *

+ * 描述 + *

+ * + * @author 沈松 + * @since 2021/12/29 18:50 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/system/develop") +public class GeneratorController extends BaseController { + + private DataSourceProperties dataSourceProperties; + + /** + * 访问[代码生成]页面 + * + * @return 页面跳转 + */ + @RequestMapping("generator") + public String generatorIndex() { + return "system/advanced/generator"; + } + + @GetMapping("/generator/list") + @ResponseBody + public BaseResult getTableList() { + // 获取链接数据库的基本信息,并填入配置类 + DataSourceConfig dsConfig = new DataSourceConfig(); + dsConfig.setUrl(dataSourceProperties.getUrl())// + .setSchemaName("public") //数据库 schema name + .setDbType(DbType.MYSQL) + .setDriverName(dataSourceProperties.getDriverClassName()) + .setUsername(dataSourceProperties.getUsername()) + .setPassword(dataSourceProperties.getPassword()); + + // 策略配置(数据库表配置) + StrategyConfig strategyConfig = new StrategyConfig(); + strategyConfig + .setNaming(NamingStrategy.underline_to_camel) // 数据库表映射到实体的命名策略:下划线转驼峰 + .setColumnNaming(NamingStrategy.underline_to_camel) // 数据库表字段映射到实体的命名策略:下划线转驼峰 + .setEntityLombokModel(true) // 实体是否为lombok模型(默认 false) + .setControllerMappingHyphenStyle(true); // 驼峰转连字符 + + // 获取所有的表 + ConfigBuilder configBuilder = new ConfigBuilder(null, dsConfig, strategyConfig, null, null); + List tableInfos = configBuilder.getTableInfoList(); + return success(200, tableInfos); + } + + /** + * 生成代码 + * + * @param projectPack 项目路径 + * @param moduleName 模块名 + * @param parentPack 父包名 + * @param author 作者 + * @param tableName 表名 + * @return 结果 + */ + @PostMapping("/generator/create") + @ResponseBody + public BaseResult CodeGenerator(String projectPack, String moduleName, String parentPack, String author, String tableName) { + // 代码生成器类 + AutoGenerator mpg = new AutoGenerator(); + + // 项目根目录 + String projectPath = System.getProperty("user.dir"); + // D:\IdeaProjects\2021_ExciteCMS\ExciteCMS + + // 六类文件的保存路径设置,可以根据自己项目的实际情况修改 + String entityPath = projectPath + "/ss-" + moduleName + projectPack + moduleName + "/entity/"; + String servicePath = projectPath + "/ss-" + moduleName + projectPack + moduleName + "/service/"; + String serviceImplPath = projectPath + "/ss-" + moduleName + projectPack + moduleName + "/service/impl/"; + String mapperPath = projectPath + "/ss-" + moduleName + projectPack + moduleName + "/mapper"; + String mapperXmlPath = projectPath + "/ss-" + moduleName + "/src/main/resources/mapper/"; + String controllerPath = projectPath + "/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/" + moduleName + "/"; + + // 1. 全局配置 + GlobalConfig globalConfig = new GlobalConfig(); + globalConfig + // 代码生成的目录 +// .setOutputDir(projectPath + "/src/main/java") + .setAuthor(author) // 修改项目作者 + .setOpen(false) // 是否打开输出目录 + .setIdType(IdType.ASSIGN_ID) // 主键策略 + .setFileOverride(false) // 是否覆盖已有文件 + .setBaseResultMap(true) // 是否开启 BaseResultMap(XML文件) + .setBaseColumnList(true); // 是否开启 baseColumnList(XML文件) +// .setServiceName(""); + + //把全局配置添加到代码生成器主类 + mpg.setGlobalConfig(globalConfig); + + // 2. 数据源配置 + DataSourceConfig dsConfig = new DataSourceConfig(); + dsConfig + // 数据库链接URL + .setUrl(dataSourceProperties.getUrl()) + // .setSchemaName("public") //数据库 schema name + .setDbType(DbType.MYSQL) // 数据库类型 + .setDriverName(dataSourceProperties.getDriverClassName()) + .setUsername(dataSourceProperties.getUsername()) + .setPassword(dataSourceProperties.getPassword()); + + // 把数据源配置添加到代码生成器主类 + mpg.setDataSource(dsConfig); + + // 3. 包配置 + PackageConfig pkConfig = new PackageConfig(); + // 添加这个后 会以一个实体为一个模块 比如user实体会生成user模块 每个模块下都会生成三层 +// pkConfig.setModuleName(scanner("模块名(系统端建议system,客户端建议client)")); + // 父包名。如果为空,将下面子包名必须写写完整的包路径。如果不为空,只需写子包名。 + pkConfig.setParent(parentPack) + // 子包名 + .setEntity(moduleName + ".entity") // 实体类 Entity包名 + .setXml("mapper") // 持久层 Mapper.xml 包名 + .setMapper(moduleName + ".mapper") // 持久层 Mapper.java 包名 + .setService(moduleName + ".service") // 服务层 Service.java 包名 + .setServiceImpl(moduleName + ".service.impl") // 服务层 ServiceImpl.java 包名 + .setController("admin.controller." + moduleName); // 控制层 Controller.java 包名 + + //设置自定义输出目录(分布式项目使用) + Map pathInfo = new HashMap<>(); + + pathInfo.put(ConstVal.ENTITY_PATH, entityPath); + pathInfo.put(ConstVal.MAPPER_PATH, mapperPath); + // pathInfo.put(ConstVal.XML_PATH, mapperXmlPath); + pathInfo.put(ConstVal.SERVICE_PATH, servicePath); + pathInfo.put(ConstVal.SERVICE_IMPL_PATH, serviceImplPath); + pathInfo.put(ConstVal.CONTROLLER_PATH, controllerPath); + + pkConfig.setPathInfo(pathInfo); + + // 把包配置添加到代码生成器主类 + mpg.setPackageInfo(pkConfig); + + // 4. 自定义配置【这是MyBatisPlus 3.x 新增的】 + InjectionConfig cfg = new InjectionConfig() { + @Override + public void initMap() { + // to do nothing + } + }; + // 如果模板引擎是 freemarker + String templatePath = "/templates/mapper.xml.ftl"; + // 如果模板引擎是 velocity + // String templatePath = "/templates/mapper.xml.vm"; + + // 自定义输出配置 + List focList = new ArrayList<>(); + // 自定义配置会被优先输出 + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + // 自定义输出文件名称,如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!! + return mapperXmlPath + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; + } + }); + cfg.setFileOutConfigList(focList); + mpg.setCfg(cfg); + // 配置模板 + TemplateConfig templateConfig = new TemplateConfig(); + templateConfig.setXml(null); + mpg.setTemplate(templateConfig); + + // 5. 策略配置(数据库表配置) + StrategyConfig strategyConfig = new StrategyConfig(); + + strategyConfig + .setNaming(NamingStrategy.underline_to_camel) // 数据库表映射到实体的命名策略:下划线转驼峰 + .setColumnNaming(NamingStrategy.underline_to_camel) // 数据库表字段映射到实体的命名策略:下划线转驼峰 + .setEntityLombokModel(true) // 实体是否为lombok模型(默认 false) + // .setSuperEntityClass("com.zxdmy.wx.mp.wechat.common.BaseEntity") // 设置实体类的父类(如果启用,实体类会增加BaseEntity的继承) + .setSuperControllerClass("com.zxdmy.excite.common.base.BaseController") // 设置控制类的父类(如果启用,控制类会增加BaseController的继承) + // 提示输入生成的表名 + .setInclude(tableName) + // .setExclude("***") // 需要排除的表名,允许正则表达式 + // .setSuperEntityColumns("id"); // 实体类主键名称设置(如果启用,生成的实体类没有此字段) + // .setTablePrefix(pc.getModuleName() + "_") // 表前缀符(如果启用,生成的所有文件名没有此前缀) + .setControllerMappingHyphenStyle(true); // 驼峰转连字符 + + // 把数据库配置添加到代码生成器主类 + mpg.setStrategy(strategyConfig); + + // 在代码生成器主类上配置模板引擎,选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有! + mpg.setTemplateEngine(new FreemarkerTemplateEngine()); + // 开始执行 + try { + mpg.execute(); + } catch (Exception e) { + return error(e.getMessage()); + } + return success("表" + tableName + "的代码生成成功!"); + } + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/advanced/MonitorController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/advanced/MonitorController.java new file mode 100644 index 0000000..576e6e8 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/advanced/MonitorController.java @@ -0,0 +1,41 @@ +package com.zxdmy.excite.admin.controller.advanced; + +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.framework.oshi.Server; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + *

+ * 描述 + *

+ * + * @author 沈松 + * @since 2022/1/22 21:18 + */ +@Controller +@RequestMapping("/system/monitor") +public class MonitorController extends BaseController { + + + @RequestMapping("server") + public String goServerMonitor() { + return "system/advanced/monitorServer"; + } + + @PostMapping("/server") + @ResponseBody + public BaseResult serverMonitor() { + Server server = new Server(); + try { + server.copyTo(); + return success("获取服务器信息成功!", server); + } catch (Exception e) { + return error("获取服务器信息失败!"); + } + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/account/AccountDepartmentController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/account/AccountDepartmentController.java new file mode 100644 index 0000000..716b8d2 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/account/AccountDepartmentController.java @@ -0,0 +1,237 @@ +package com.zxdmy.excite.admin.controller.cloud.account; + +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.cloud.account.CloudCompany; +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartment; +import com.zxdmy.excite.system.entity.dto.DepartmentTreeDTO; +import com.zxdmy.excite.system.entity.dto.DepartmentUserTreeNode; +import com.zxdmy.excite.system.entity.req.account.ReqDepartment; +import com.zxdmy.excite.system.entity.vo.account.DepartmentVo; +import com.zxdmy.excite.system.service.cloud.account.ICloudCompanyService; +import com.zxdmy.excite.system.service.cloud.account.ICloudDepartmentService; +import lombok.AllArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/account/department/") +public class AccountDepartmentController extends BaseController { + + private ICloudDepartmentService iCloudDepartmentService; + private ICloudCompanyService iCloudCompanyService; + @RequestMapping("index") + public String index() { + return "cloud/account/department/index"; + } + + + @GetMapping("/list") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, ReqDepartment data) { + try { + PageList dataPage = iCloudDepartmentService.queryByPage(page, limit, data); + return success("获取数据成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + @RequestMapping("add") + public String add() { + return "cloud/account/department/add"; + } + + @PostMapping("/addSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult addSave(@Validated ReqDepartment data) { + try { + if(null == iCloudDepartmentService.getByData(data)){ + if(iCloudDepartmentService.saveData(data)==1){ + return success("操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @RequestMapping("edit/{id}") + public String edit(@PathVariable String id, ModelMap map) { + CloudDepartment data = iCloudDepartmentService.getById(id); + // 加载至前端 + if (data == null) { + map.put("code", 404); + map.put("msg", "数据不存在!"); + return "error/error"; + } + map.put("id", id); + return "cloud/account/department/edit"; + } + + @GetMapping("/getData") + @ResponseBody + public BaseResult getData(ReqDepartment req) { + try { + DepartmentVo data = iCloudDepartmentService.getByData(req); + if(null!=data){ + return success("获取数据成功",data); + }else{ + return error(400, "数据不存在!"); + } + + + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @PostMapping("/editSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult editSave(@Validated ReqDepartment data) { + try { + if(null == iCloudDepartmentService.getByData(data)){ + if(iCloudDepartmentService.updateData(data)==1){ + return success(200,"操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @PostMapping("/delete") + @ResponseBody + @AnnotationSaveReLog + public BaseResult delete(String id) { + try { + int result = iCloudDepartmentService.deleteById(id); + if (result == 1) { + return success(200, "删除成功!"); + }else{ + return error("删除失败!"); + } + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + + @GetMapping("/query") + @ResponseBody + public BaseResult query() { + try { + List data = new ArrayList<>(); + List company = iCloudCompanyService.getList(); + for (CloudCompany cloudCompany :company) { + DepartmentTreeDTO departmentTreeDTO = new DepartmentTreeDTO(); + departmentTreeDTO.setId(cloudCompany.getId()); + departmentTreeDTO.setTitle(cloudCompany.getCompanyName()); + departmentTreeDTO.setSpread(true); + List dataPage = iCloudDepartmentService.getList(cloudCompany.getId()); + List department = buildDepartmentTree(dataPage); + departmentTreeDTO.setChildren(department); + data.add(departmentTreeDTO); + } + + return success(200, "获取数据成功!",data); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + @GetMapping("/query1") + @ResponseBody + public BaseResult query1() { + try { + List data = new ArrayList<>(); + List company = iCloudCompanyService.getList(); + for (CloudCompany cloudCompany :company) { + CloudDepartment cloudDepartment = new CloudDepartment(); + cloudDepartment.setId(cloudCompany.getId()); + cloudDepartment.setDepartmentName(cloudCompany.getCompanyName()); + DepartmentUserTreeNode departmentTreeDTO = new DepartmentUserTreeNode(cloudDepartment); + List tree = iCloudDepartmentService.buildDepartmentUserTree(cloudCompany.getId()); + departmentTreeDTO.setChildren(tree); + data.add(departmentTreeDTO); + System.out.println(tree); + } + + return success(200, "获取数据成功!",data); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + public List buildDepartmentTree(List departments) { + // 1. 按parentId分组 + Map> parentMap = new HashMap<>(); + // 2. 创建所有节点的映射 + Map nodeMap = new HashMap<>(); + // 3. 转换并分组 + for (CloudDepartment dept : departments) { + DepartmentTreeDTO node = new DepartmentTreeDTO(); + BeanUtils.copyProperties(dept, node); + node.setChildren(new ArrayList<>()); + nodeMap.put(dept.getId(), node); + + Long parentId = dept.getDepartmentParentId(); + if (parentId == null) { + parentId = 0L; // 将null转换为0,作为根节点的父ID + } + + parentMap.computeIfAbsent(parentId, k -> new ArrayList<>()) + .add(node); + } + + // 4. 构建树形结构 + List rootList = parentMap.getOrDefault(0L, new ArrayList<>()); + + // 5. 递归构建子节点 + for (Long parentId : parentMap.keySet()) { + if (parentId.equals(0L)) continue; + + DepartmentTreeDTO parentNode = nodeMap.get(parentId); + if (parentNode != null) { + parentNode.setChildren(parentMap.get(parentId)); + } + } + + // 6. 排序(按department_sort) + sortTreeNodes(rootList); + + return rootList; + } + + private void sortTreeNodes(List nodes) { + if (nodes == null || nodes.isEmpty()) return; + + // 按排序字段排序 + nodes.sort(Comparator.comparing(DepartmentTreeDTO::getDepartmentSort)); + + // 递归排序子节点 + for (DepartmentTreeDTO node : nodes) { + if (node.getChildren() != null && !node.getChildren().isEmpty()) { + sortTreeNodes(node.getChildren()); + } + } + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/account/AccountEnterpriseController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/account/AccountEnterpriseController.java new file mode 100644 index 0000000..c468f0a --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/account/AccountEnterpriseController.java @@ -0,0 +1,144 @@ +package com.zxdmy.excite.admin.controller.cloud.account; + +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.cloud.account.CloudCompany; +import com.zxdmy.excite.system.entity.req.account.ReqCompany; +import com.zxdmy.excite.system.entity.vo.account.CompanyVo; +import com.zxdmy.excite.system.service.cloud.account.ICloudCompanyService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/account/company") +public class AccountEnterpriseController extends BaseController { + + private ICloudCompanyService iCloudCompanyService; + + + @RequestMapping("index") + public String index() { + return "cloud/account/enterprise/index"; + } + + + @GetMapping("/list") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, ReqCompany data) { + try { + PageList dataPage = iCloudCompanyService.queryByPage(page, limit, data); + return success("获取数据成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + @RequestMapping("add") + public String add() { + return "cloud/account/enterprise/add"; + } + + @PostMapping("/addSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult addSave(@Validated ReqCompany data) { + try { + if(null == iCloudCompanyService.getByData(data)){ + if(iCloudCompanyService.saveData(data)==1){ + return success("操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @RequestMapping("edit/{id}") + public String edit(@PathVariable String id, ModelMap map) { + CloudCompany data = iCloudCompanyService.getById(id); + // 加载至前端 + if (data == null) { + map.put("code", 404); + map.put("msg", "数据不存在!"); + return "error/error"; + } + map.put("id", id); + return "cloud/account/enterprise/edit"; + } + + @GetMapping("/getData") + @ResponseBody + public BaseResult getData(String id) { + try { + CloudCompany data = iCloudCompanyService.getById(id); + if(null!=data){ + return success("获取数据成功",data); + }else{ + return error(400, "数据不存在!"); + } + + + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @PostMapping("/editSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult editSave(@Validated ReqCompany data) { + try { + if(null == iCloudCompanyService.getByData(data)){ + if(iCloudCompanyService.updateData(data)==1){ + return success(200,"操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @PostMapping("/delete") + @ResponseBody + @AnnotationSaveReLog + public BaseResult delete(String id) { + try { + int result = iCloudCompanyService.deleteById(id); + if (result == 1) { + return success(200, "删除成功!"); + }else{ + return error("删除失败!"); + } + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + @GetMapping("/query") + @ResponseBody + public BaseResult query() { + try { + List dataPage = iCloudCompanyService.queryByData(); + return success("获取数据成功", dataPage); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/account/AccountUserController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/account/AccountUserController.java new file mode 100644 index 0000000..305e3a1 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/account/AccountUserController.java @@ -0,0 +1,340 @@ +package com.zxdmy.excite.admin.controller.cloud.account; + +import cn.dev33.satoken.stp.SaTokenInfo; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.config.ExciteConfig; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.common.enums.SystemCode; +import com.zxdmy.excite.framework.aop.AnnotationSaveLoginLog; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.cloud.account.CloudCompany; +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartment; +import com.zxdmy.excite.system.entity.dto.DepartmentTreeDTO; +import com.zxdmy.excite.system.entity.req.account.ReqDepartment; +import com.zxdmy.excite.system.entity.vo.account.DepartmentVo; +import com.zxdmy.excite.system.service.ISysUserService; +import com.zxdmy.excite.system.service.cloud.account.ICloudCompanyService; +import com.zxdmy.excite.system.service.cloud.account.ICloudDepartmentService; +import lombok.AllArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpSession; +import java.util.*; + +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/account/user/") +public class AccountUserController extends BaseController { + + private ICloudDepartmentService iCloudDepartmentService; + private ICloudCompanyService iCloudCompanyService; + private ISysUserService userService; + private ExciteConfig exciteConfig; + @RequestMapping("index") + public String index() { + return "cloud/account/user/index"; + } + + @RequestMapping("goAdd/{id}") + public String goAdd(@PathVariable String id,ModelMap map) { + map.put("id", id); + return "cloud/account/user/add"; + } + + @RequestMapping("goEdit/{id}") + public String goEdit(@PathVariable String id, ModelMap map) { + // 获取该用户的信息 + SysUser user = userService.getById(id); + // 加载至前端 + if (user == null) { + map.put("code", 404); + map.put("msg", "用户不存在!"); + return "error/error"; + } + map.put("user", user); + return "cloud/account/user/edit"; + } + @RequestMapping("goAuthDepartment/{id}") + public String goAuthDepartment(@PathVariable String id, ModelMap map) { + // 获取该用户的信息 + SysUser user = userService.getById(id); + // 加载至前端 + if (user == null) { + map.put("code", 404); + map.put("msg", "用户不存在!"); + return "error/error"; + } + map.put("user", user); + return "cloud/account/user/editDepartment"; + } + + @RequestMapping("selectDepartment") + public String selectDepartment() { + return "cloud/account/user/selectDepartment"; + } + @RequestMapping("updateDepartment/{id}") + public String selectDepartment(@PathVariable String id, ModelMap map) { + map.put("id", id); + return "cloud/account/user/updateDepartment"; + } + @PostMapping(value = "/changeDepartment") + @ResponseBody + public BaseResult changeDepartment(String userId, String departmentId) { + try { + if (iCloudDepartmentService.changeDepartment(userId, departmentId)==1) { + return success(200, "转换成功!"); + } + return success("转换失败,请重试!"); + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + + } + + /** + * 接口功能:获取用户列表 + * + * @param page 当前页面 + * @param limit 每页请求数 + * @param username 检索用户名 + * @param account 检索电话或邮箱 + * @return JSON:用户列表 | 错误信息 + */ + @GetMapping(value = "/list") + @ResponseBody + public BaseResult getUserList(Integer page, Integer limit, String username, String account,String departmentId) { + Page userPage = userService.getPage(page, limit, username, account); + if (null != userPage) { + return success("查询成功", userPage.getRecords(), (int) userPage.getTotal()); + } else { + return error("查询失败,用户不存在"); + } + } + + @GetMapping(value = "/getPageList") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, String username, String phone,String departmentId) { + PageList dataPage = userService.queryByPage(page, limit, username,phone,departmentId); + if (null != dataPage) { + return success("查询成功", dataPage.getList(), (int) dataPage.getTotal()); + } else { + return error("查询失败,用户不存在"); + } + } + + /** + * 接口功能:添加用户 + * 基本逻辑:接收前端的用户信息-->校验与初始化新用户信息-->添加至[用户表]-->获取新添加用户的ID-->用户ID与角色ID添加至[用户角色关联表]. + * + * @param user 用户信息 + * @param roleIds 用户分配的角色信息 + * @return JSON:成败结果 + * @apiNote 启用注解[@AnnotationSaveReLog]保存请求日志 + */ + @PostMapping(value = "/add") + @ResponseBody + @AnnotationSaveReLog + public BaseResult add(SysUser user, Integer[] roleIds,String[] roleIds1,String departmentId) { + // 新建用户:其邮箱或手机号、密码不能为空,因为这是登录凭证. + if (null != user && null != user.getPassword() && (null != user.getLoginName() || null != user.getPhone())) { + // 解密 + user.setPassword(SecureUtil.md5(this.decrypt(user.getPassword()))); + // 添加 + if (userService.saveData(user, roleIds,roleIds1,departmentId) > 0) { + return success("新用户添加成功!"); + } else { + return error("新用户添加失败,请重试!"); + } + } + return error("用户信息(账号或手机号、密码)不能为空,请重试!"); + } + + /** + * 接口功能:更新用户基本信息(不含角色信息) + * + * @param user 用户信息 + * @return JSON:成败结果 + * @apiNote 启用注解[@AnnotationSaveReLog]保存请求日志 + */ + @PostMapping(value = "/update") + @ResponseBody + @AnnotationSaveReLog + public BaseResult update(SysUser user) { + // 编辑用户基本信息:用户名、头像、性别、邮箱和手机号。 + if (null != user && null != user.getId()) { + // 其他信息(状态、密码)不能通过此接口修改,故其应为null. + if (null == user.getStatus() && null == user.getPassword()) { + if (userService.save(user, null) > 0) { + return success("用户信息编辑成功!"); + } else { + return error("用户信息编辑失败,请重试!"); + } + } else { + return error("接口请求信息错误!"); + } + } else { + return error("用户信息不能为空,请重试!"); + } + } + + /** + * 接口功能:删除用户 + * 基本逻辑:删除该用户的角色信息[用户-角色关联表]-->删除用户 + * + * @param userIds 用户ID列表 + * @return JSON:成败 + * @apiNote 启用注解[@AnnotationSaveReLog]保存请求日志 + */ + @PostMapping(value = "/delete") + @ResponseBody + @AnnotationSaveReLog + public BaseResult delete(Integer[] userIds) { + try { + if (userService.deleteUserById(userIds)[0] > 0) { + return success("用户删除成功"); + } + return error("用户删除失败"); + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:给指定用户分配角色 + * + * @param id 用户ID + * @param roleIds 角色信息列表 + * @return 分配结果 + */ + @PostMapping(value = "/authRole") + @ResponseBody + public BaseResult setRole(Long id, String[] roleIds) { + try { + if (userService.setCloudRoleForUser(String.valueOf(id), roleIds)) { + return success(200, "分配角色成功!"); + } + return success("分配角色失败,请重试!"); + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + + } + + /** + * 接口功能:改变用户的状态 + * + * @param status 新状态:1-正常 0-禁用 + * @param userIds 用户ID列表 + * @return 修改结果 + */ + @PostMapping(value = "/changeStatus/{status}") + @ResponseBody + public BaseResult changeStatus(@PathVariable String status, Integer[] userIds) { + try { + int[] result = userService.changeStatus(Integer.parseInt(status), userIds); + // 没有失败 + if (result[0] != 0 && result[1] == 0) { + return success(200, "用户状态修改成功!"); + } + // 有成功的 + else if (result[0] != 0) { + return success(200, result[0] + "个角色状态更新成功," + result[1] + "个失败!"); + } else { + return success(500, "用户状态修改失败,请重试!"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:重置密码 + * + * @param userId 用户ID + * @param newPassword 新密码 + * @param newPassword2 新密码 + * @return 重置结果 + */ + @PostMapping(value = "/resetPassword") + @ResponseBody + @AnnotationSaveReLog + public BaseResult resetPassword(String userId, String newPassword, String newPassword2) { + if (null == userId || null == newPassword || null == newPassword2) { + return error("输入信息有误,请重新输入!"); + } + // 密码先解密 + newPassword = this.decrypt(newPassword); + newPassword2 = this.decrypt(newPassword2); + // 密码相同 + if (newPassword.equals(newPassword2)) { + SysUser user = new SysUser(); + try { + user.setId(Integer.parseInt(userId)); + // 密码MD5加密 + user.setPassword(SecureUtil.md5(newPassword)); + if (userService.save(user, null) > 0) { + return success("密码重置成功!"); + } else { + error("密码重置失败,请重试!"); + } + } catch (Exception e) { + return error(e.getMessage()); + } + } + return error("密码重置失败,新密码不一致!"); + } + + /** + * 接口功能:获取指定角色所分配的用户列表(拥有/不拥有此角色) + * + * @param roleId 角色ID + * @param have 是否用于此角色:0-不拥有 | 1-拥有 + * @return 用户列表 + */ + @GetMapping("/listForRole/{have}/{roleId}") + @ResponseBody + public BaseResult getUserListForRole(@PathVariable("have") String have, @PathVariable("roleId") Long roleId) { + try { + // 拥有 此角色 + List userList; + if (have.equals("1")) { + userList = userService.selectUsersByCloudUploadRoleId(String.valueOf(roleId)); + } + // 不拥有 此角色 + else { + userList = userService.selectUsersByCloudUploadRoleIdNotIn(String.valueOf(roleId)); + } + return success(200, "获取成功", userList); + } catch (Exception e) { + return error(e.getMessage()); + } + } + + + + /** + * 私有方法:解密密码 + * + * @param encrypt 加密密码 + * @return 解密密码 + */ + private String decrypt(String encrypt) { + // 根据私钥生成新的对象 + RSA rsa = new RSA(exciteConfig.getRsaPrivateKey(), null); + byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey); + return StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8); + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/collect/CollectController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/collect/CollectController.java new file mode 100644 index 0000000..0b4be83 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/collect/CollectController.java @@ -0,0 +1,91 @@ +package com.zxdmy.excite.admin.controller.cloud.collect; + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.cloud.account.CloudCompany; +import com.zxdmy.excite.system.entity.cloud.space.CloudFile; +import com.zxdmy.excite.system.entity.req.account.ReqCompany; +import com.zxdmy.excite.system.entity.req.collection.ReqCloudUserCollection; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.service.cloud.collection.ICloudUserCollectionService; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 系统菜单/权限表 前端控制器 + * + * @author 沈松 + * @since 2021-09-12 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/collect/") +public class CollectController extends BaseController { + + private ICloudUserCollectionService iCloudUserCollectionService; + + /** + * @return 页面:【菜单管理】页面入口 + */ + @RequestMapping("index") + public String index() { + return "cloud/collect/index"; + } + + + @GetMapping("/list") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, ReqCloudUserCollection data) { + try { + data.setUserId(StpUtil.getLoginIdAsInt()); + PageList dataPage = iCloudUserCollectionService.queryByPage(page, limit, data); + return success("获取列表成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + @PostMapping("/collection") + @ResponseBody + @AnnotationSaveReLog + public BaseResult collection(@Validated ReqCloudUserCollection data) { + try { + data.setUserId(StpUtil.getLoginIdAsInt()); + if(null == iCloudUserCollectionService.getByData(data)){ + if(iCloudUserCollectionService.saveData(data)==1){ + return success("操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + @PostMapping("/removeCollection") + @ResponseBody + @AnnotationSaveReLog + public BaseResult removeCollection(String id) { + try { + if(iCloudUserCollectionService.deleteById(id)==1){ + return success("操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/lately/CloudUserLatelyController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/lately/CloudUserLatelyController.java new file mode 100644 index 0000000..2090ae3 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/lately/CloudUserLatelyController.java @@ -0,0 +1,76 @@ +package com.zxdmy.excite.admin.controller.cloud.lately; + + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.req.collection.ReqCloudUserCollection; +import com.zxdmy.excite.system.entity.req.lately.ReqCloudUserLately; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.service.cloud.collection.ICloudUserCollectionService; +import com.zxdmy.excite.system.service.cloud.lately.ICloudUserLatelyService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + *

+ * 最近文件表 前端控制器 + *

+ * + * @author 沈松 + * @since 2026-01-29 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/lately") +public class CloudUserLatelyController extends BaseController { + + private ICloudUserLatelyService iCloudUserLatelyService; + + @RequestMapping("index") + public String index() { + return "cloud/lately/index"; + } + + + @GetMapping("/list") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, ReqCloudUserLately data) { + try { + data.setUserId(StpUtil.getLoginIdAsInt()); + PageList dataPage = iCloudUserLatelyService.queryByPage(page, limit, data); + return success("获取列表成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + @PostMapping("/addSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult addSave(@Validated ReqCloudUserLately data) { + try { + data.setUserId(StpUtil.getLoginIdAsInt()); + if(null == iCloudUserLatelyService.getByData(data)){ + if(iCloudUserLatelyService.saveData(data)==1){ + return success("操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/my/CloudMyFileController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/my/CloudMyFileController.java new file mode 100644 index 0000000..813189d --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/my/CloudMyFileController.java @@ -0,0 +1,60 @@ +package com.zxdmy.excite.admin.controller.cloud.my; + + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.entity.cloud.space.CloudFile; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleService; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleUserService; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileService; +import lombok.AllArgsConstructor; +import org.apache.commons.beanutils.BeanUtils; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + *

+ * 文件表 前端控制器 + *

+ * + * @author ss + * @since 2026-01-28 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/my") +public class CloudMyFileController extends BaseController { + + + private ICloudFileService iCloudFileService; + private ICloudRoleUserService iCloudRoleUserService; + private ICloudRoleService iCloudRoleService; + @RequestMapping("index") + public String index() { + return "cloud/my/index"; + } + + + @GetMapping("/list") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, ReqCloudFile data) { + try { + data.setCreatorId(StpUtil.getLoginIdAsInt()); + data.setFileFolder(1); + PageList dataPage = iCloudFileService.queryByPage(page, limit, data); + return success("获取数据成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/recycle/CloudMyRecycleController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/recycle/CloudMyRecycleController.java new file mode 100644 index 0000000..0373b11 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/recycle/CloudMyRecycleController.java @@ -0,0 +1,85 @@ +package com.zxdmy.excite.admin.controller.cloud.recycle; + + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + + +/** + *

+ * 文件表 前端控制器 + *

+ * + * @author ss + * @since 2026-01-28 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/myRecycle") +public class CloudMyRecycleController extends BaseController { + + + private ICloudFileService iCloudFileService; + + @RequestMapping("index") + public String index() { + return "cloud/recycle/index"; + } + + + @GetMapping("/list") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, ReqCloudFile data) { + try { + data.setCreatorId(StpUtil.getLoginIdAsInt()); + PageList dataPage = iCloudFileService.queryByRecyclePage(page, limit, data); + return success("获取数据成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + @PostMapping("/recover") + @ResponseBody + public BaseResult recover(String id) { + try { + int result = iCloudFileService.recover(id); + if (result == 1) { + return success(200, "恢复成功!"); + }else{ + return error("恢复失败!"); + } + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + @PostMapping("/foreverDelete") + @ResponseBody + @AnnotationSaveReLog + public BaseResult foreverDelete(String id) { + try { + int result = iCloudFileService.deleteById(id); + if (result == 1) { + return success(200, "删除成功!"); + }else{ + return error("删除失败!"); + } + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/role/CloudRoleController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/role/CloudRoleController.java new file mode 100644 index 0000000..3962d14 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/role/CloudRoleController.java @@ -0,0 +1,286 @@ +package com.zxdmy.excite.admin.controller.cloud.role; + + +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.SysRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.entity.dto.RoleTreeDTO; +import com.zxdmy.excite.system.entity.req.role.ReqRole; +import com.zxdmy.excite.system.entity.vo.role.RoleVo; +import com.zxdmy.excite.system.service.ISysUserService; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleService; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleUserService; +import lombok.AllArgsConstructor; +import org.apache.commons.beanutils.BeanUtils; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import org.springframework.stereotype.Controller; +import com.zxdmy.excite.common.base.BaseController; + +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * 云盘权限表 前端控制器 + *

+ * + * @author ss + * @since 2026-01-27 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/role/") +public class CloudRoleController extends BaseController { + private ICloudRoleService iCloudRoleService; + private ISysUserService iSysUserService; + private ICloudRoleUserService iCloudRoleUserService; + + + @RequestMapping("index") + public String index() { + return "cloud/role/role/index"; + } + + @GetMapping("/list") + @ResponseBody + public BaseResult getRoleList(Integer page, Integer limit, ReqRole data) { + try { + PageList dataPage = iCloudRoleService.queryByPage(page, limit, data); + return success("获取数据成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @RequestMapping("add") + public String add() { + return "cloud/role/role/add"; + } + + @PostMapping("/addSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult addSave(@Validated ReqRole data) { + try { + if(null == iCloudRoleService.getByData(data)){ + if(iCloudRoleService.saveData(data)==1){ + return success("操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @RequestMapping("edit/{id}") + public String edit(@PathVariable String id, ModelMap map) { + CloudRole data = iCloudRoleService.getById(id); + // 加载至前端 + if (data == null) { + map.put("code", 404); + map.put("msg", "数据不存在!"); + return "error/error"; + } + map.put("id", id); + return "cloud/role/role/edit"; + } + + @GetMapping("/getData") + @ResponseBody + public BaseResult getData(String id) { + try { + CloudRole data = iCloudRoleService.getById(id); + if(null!=data){ + return success("获取数据成功",data); + }else{ + return error(400, "数据不存在!"); + } + + + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @PostMapping("/editSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult editSave(@Validated ReqRole data) { + try { + RoleVo roleVo =iCloudRoleService.getByData(data); + CloudRole cloudRole = iCloudRoleService.getById(data.getId()); + if(roleVo==null){ + if(iCloudRoleService.updateData(data)==1){ + return success(200,"操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + if(cloudRole.getRoleName().equals(roleVo.getRoleName())){ + if(iCloudRoleService.updateData(data)==1){ + return success(200,"操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @PostMapping("/delete") + @ResponseBody + @AnnotationSaveReLog + public BaseResult delete(String id) { + try { + int result = iCloudRoleService.deleteById(id); + if (result == 1) { + return success(200, "删除成功!"); + }else{ + return error("删除失败!"); + } + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + @PostMapping(value = "/changeUploadStatus/{status}") + @ResponseBody + public BaseResult changeUploadStatus(@PathVariable String status, String[] ids) { + try { + int[] result = iCloudRoleService.changeUploadStatus(Integer.parseInt(status), ids); + // 没有失败 + if (result[0] != 0 && result[1] == 0) { + return success(200, "修改成功!"); + } + // 有成功的 + else if (result[0] != 0) { + return success(200, result[0] + "个更新成功," + result[1] + "个失败!"); + } else { + return success(500, "修改失败,请重试!"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + @PostMapping(value = "/changeDownStatus/{status}") + @ResponseBody + public BaseResult changeDownStatus(@PathVariable String status, String[] ids) { + try { + int[] result = iCloudRoleService.changeDownStatus(Integer.parseInt(status), ids); + // 没有失败 + if (result[0] != 0 && result[1] == 0) { + return success(200, "修改成功!"); + } + // 有成功的 + else if (result[0] != 0) { + return success(200, result[0] + "个更新成功," + result[1] + "个失败!"); + } else { + return success(500, "修改失败,请重试!"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @PostMapping(value = "/changeDeleteStatus/{status}") + @ResponseBody + public BaseResult changeDeleteStatus(@PathVariable String status, String[] ids) { + try { + int[] result = iCloudRoleService.changeDeleteStatus(Integer.parseInt(status), ids); + // 没有失败 + if (result[0] != 0 && result[1] == 0) { + return success(200, "修改成功!"); + } + // 有成功的 + else if (result[0] != 0) { + return success(200, result[0] + "个更新成功," + result[1] + "个失败!"); + } else { + return success(500, "修改失败,请重试!"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @RequestMapping("goShowUser/{id}") + public String goShowUser(@PathVariable String id, ModelMap map) { + try { + CloudRole role = iCloudRoleService.getById(id); + if (null == role) { + map.put("code", 500); + map.put("msg", "可能原因:该角色禁止编辑,该角色已被禁用!"); + return "error/error"; + } else { + RoleVo roleVo = new RoleVo(); + BeanUtils.copyProperties(roleVo, role); + map.put("role", roleVo); + return "cloud/role/role/authUser"; + } + } catch (Exception e) { + // 发生异常,一般就是数字转换出错 + System.err.println(e.getMessage()); + return "error/500"; + } + } + + @PostMapping("/authUser/{type}") + @ResponseBody + @AnnotationSaveReLog + public BaseResult authForUser(@PathVariable("type") String type, String roleId, String[] userIds) { + try { + // 添加授权 + if (type.equals("auth")) { + if (iCloudRoleService.authRoleForUsers(roleId, userIds)) + return success(200, "添加授权成功!"); + else + return error("授权失败,请重试!"); + } + // 取消授权 + else if (type.equals("revoke")) { + int[] result = iCloudRoleService.revokeRoleForUsers(roleId, userIds); + if (result[1] == 0) + return success(200, "取消授权成功!"); + else if (result[0] == 0) + return error("取消授权失败,请重试!"); + else + return success(result[0] + "个用户取消授权成功," + result[1] + "个失败!"); + } + return error("访问错误!"); + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + + @GetMapping("/listForUser/{userId}") + @ResponseBody + public BaseResult getRoleListForUser(@PathVariable String userId) { + try { + List list = new ArrayList<>(); + List roleList = iCloudRoleService.getListByUserId(Integer.parseInt(userId)); + for (CloudRole cloudRole:roleList) { + RoleTreeDTO roleTreeDTO = new RoleTreeDTO(); + roleTreeDTO.setId(cloudRole.getId()); + roleTreeDTO.setName(cloudRole.getRoleName()); + list.add(roleTreeDTO); + } + return success("获取角色列表成功", list, list.size()); + } catch (Exception e) { + return error(500, "error:" + e.getMessage()); + } + } + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/role/CloudRoleUserController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/role/CloudRoleUserController.java new file mode 100644 index 0000000..bd6b4c8 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/role/CloudRoleUserController.java @@ -0,0 +1,42 @@ +package com.zxdmy.excite.admin.controller.cloud.role; + + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.service.ISysUserService; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleUserService; +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.stereotype.Controller; +import com.zxdmy.excite.common.base.BaseController; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + *

+ * 云盘权限用户表 前端控制器 + *

+ * + * @author ss + * @since 2026-01-27 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/roleUser") +public class CloudRoleUserController extends BaseController { + private ICloudRoleUserService iCloudRoleUserService; + + @GetMapping("/getRole") + @ResponseBody + public BaseResult getRole() { + try { + CloudRole data = iCloudRoleUserService.getCloudShareRole(StpUtil.getLoginIdAsInt()); + return success("获取数据成功",data); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/share/CloudShareController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/share/CloudShareController.java new file mode 100644 index 0000000..a08f9bc --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/share/CloudShareController.java @@ -0,0 +1,103 @@ +package com.zxdmy.excite.admin.controller.cloud.share; + + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleUser; +import com.zxdmy.excite.system.entity.cloud.space.CloudFile; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleService; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleUserService; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileService; +import lombok.AllArgsConstructor; +import org.apache.commons.beanutils.BeanUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; + +/** + *

+ * 文件表 前端控制器 + *

+ * + * @author ss + * @since 2026-01-28 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/share") +public class CloudShareController extends BaseController { + + + private ICloudFileService iCloudFileService; + private ICloudRoleUserService iCloudRoleUserService; + private ICloudRoleService iCloudRoleService; + @RequestMapping("index") + public String index() { + return "cloud/share/index"; + } + + + @GetMapping("/list") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, ReqCloudFile data) { + try { + CloudRole cloudRole = iCloudRoleUserService.getCloudShareRole(StpUtil.getLoginIdAsInt()); + PageList dataPage = iCloudFileService.queryByPage(page, limit, data); + if(null!=cloudRole){ + if (cloudRole.getRoleDown()>0) { + for (CloudFileVo cloudFileVo:dataPage.getList()) { + cloudFileVo.setRoleDown(1); + } + } + if (cloudRole.getRoleUpload()>0) { + for (CloudFileVo cloudFileVo:dataPage.getList()) { + cloudFileVo.setRoleUpload(1); + } + } + if (cloudRole.getRoleDelete()>0) { + for (CloudFileVo cloudFileVo:dataPage.getList()) { + cloudFileVo.setRoleDelete(1); + } + } + } + + return success("获取数据成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + @GetMapping("/getData") + @ResponseBody + public BaseResult getData(String id) { + try { + CloudFileVo data = new CloudFileVo(); + CloudFile cloudFile = iCloudFileService.getById(id); + if(null!=cloudFile){ + BeanUtils.copyProperties(data, cloudFile); + } + if(null!=cloudFile){ + return success("获取数据成功",data); + }else{ + return error(400, "数据不存在!"); + } + + + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/space/CloudFileController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/space/CloudFileController.java new file mode 100644 index 0000000..eac59c1 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/space/CloudFileController.java @@ -0,0 +1,397 @@ +package com.zxdmy.excite.admin.controller.cloud.space; + + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.entity.cloud.space.CloudFile; +import com.zxdmy.excite.system.entity.cloud.space.CloudFileRole; +import com.zxdmy.excite.system.entity.dto.FileTreeDTO; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.space.*; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleUserService; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileRoleService; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileService; +import lombok.AllArgsConstructor; +import org.apache.commons.beanutils.BeanUtils; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import org.springframework.stereotype.Controller; +import com.zxdmy.excite.common.base.BaseController; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.stream.Collectors; + +/** + *

+ * 文件表 前端控制器 + *

+ * + * @author ss + * @since 2026-01-28 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/space") +public class CloudFileController extends BaseController { + + + private ICloudFileService iCloudFileService; + private ICloudRoleUserService iCloudRoleUserService; + private ICloudFileRoleService iCloudFileRoleService; + @RequestMapping("index") + public String index() { + return "cloud/space/file/index"; + } + + + @GetMapping("/list") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, ReqCloudFile data) { + try { + CloudRole cloudRole = iCloudRoleUserService.getCloudShareRole(StpUtil.getLoginIdAsInt()); + PageList dataPage = iCloudFileService.queryByPage(page, limit, data); + if(null!=cloudRole){ + if (cloudRole.getRoleDown()>0) { + for (CloudFileVo cloudFileVo:dataPage.getList()) { + cloudFileVo.setRoleDown(1); + } + } + if (cloudRole.getRoleUpload()>0) { + for (CloudFileVo cloudFileVo:dataPage.getList()) { + cloudFileVo.setRoleUpload(1); + } + } + if (cloudRole.getRoleDelete()>0) { + for (CloudFileVo cloudFileVo:dataPage.getList()) { + cloudFileVo.setRoleDelete(1); + } + } + } + return success("获取数据成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @RequestMapping("add") + public String add() { + return "cloud/space/file/add"; + } + + @PostMapping("/addSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult addSave(@Validated ReqCloudFile data) { + try { + if(null == iCloudFileService.getByData(data)){ + if(iCloudFileService.saveData(data)==1){ + return success("操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @GetMapping("/getData") + @ResponseBody + public BaseResult getData(String id) { + try { + CloudFileVo data = new CloudFileVo(); + CloudFile cloudFile = iCloudFileService.getById(id); + if(null!=cloudFile){ + BeanUtils.copyProperties(data, cloudFile); + } + if(null!=cloudFile){ + return success("获取数据成功",data); + }else{ + return error(400, "数据不存在!"); + } + + + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @RequestMapping("edit/{id}") + public String edit(@PathVariable String id, ModelMap map) throws InvocationTargetException, IllegalAccessException { + + CloudFileVo data = new CloudFileVo(); + CloudFile cloudFile = iCloudFileService.getById(id); + if(null!=cloudFile){ + BeanUtils.copyProperties(data, cloudFile); + } + // 加载至前端 + if (cloudFile == null) { + map.put("code", 404); + map.put("msg", "数据不存在!"); + return "error/error"; + } + map.put("id", id); + return "cloud/space/file/edit"; + } + + @PostMapping("/editSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult editSave(@Validated ReqCloudFile data) { + try { + CloudFileVo cloudFileVo = iCloudFileService.getByData(data); + CloudFile cloudFile = iCloudFileService.getById(data.getId()); + if(cloudFileVo==null){ + if(iCloudFileService.updateData(data)==1){ + return success(200,"操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + if (cloudFile.getFileName().equals(data.getFileName())) { + if(iCloudFileService.updateData(data)==1){ + return success(200,"操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } + + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + @PostMapping("/delete") + @ResponseBody + @AnnotationSaveReLog + public BaseResult delete(String id) { + try { + int result = iCloudFileService.deleteById(id); + if (result == 1) { + return success(200, "删除成功!"); + }else{ + return error("删除失败!"); + } + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + + @GetMapping("/getFileRole") + @ResponseBody + public BaseResult getFileRole(String id) { + try { + CloudFilleUserVo cloudFilleUserVo = new CloudFilleUserVo(); + List dataPage = iCloudFileRoleService.getFileRole(id); + + List ids = dataPage.stream() + .map(CloudFileRoleVo::getUserId) + .collect(Collectors.toList()); + cloudFilleUserVo.setIds(ids); + + String names = dataPage.stream() + .map(CloudFileRoleVo::getUserName) + .collect(Collectors.joining(", ")); + + String userIDs = dataPage.stream() + .map(CloudFileRoleVo -> String.valueOf(CloudFileRoleVo.getId())) + .collect(Collectors.joining(", ")); + cloudFilleUserVo.setUserId(userIDs); + cloudFilleUserVo.setName(names); + return success("获取数据成功", cloudFilleUserVo); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + + @GetMapping("/getRoleFile") + @ResponseBody + public BaseResult getRoleFile(String id) { + try { + CloudRoleFolderVo cloudRoleFolderVo = new CloudRoleFolderVo(); + List dataPage = iCloudFileRoleService.getRoleFile(id); + + List ids = dataPage.stream() + .map(CloudRoleFileVo::getFileId) + .collect(Collectors.toList()); + cloudRoleFolderVo.setIds(ids); + + String names = dataPage.stream() + .map(CloudRoleFileVo::getFileName) + .collect(Collectors.joining(", ")); + + String userIDs = dataPage.stream() + .map(CloudRoleFileVo -> String.valueOf(CloudRoleFileVo.getId())) + .collect(Collectors.joining(", ")); + cloudRoleFolderVo.setRoleId(userIDs); + cloudRoleFolderVo.setName(names); + return success("获取数据成功", cloudRoleFolderVo); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @GetMapping("/getRoleFileCheck") + @ResponseBody + public BaseResult getRoleFileCheck(String id) { + try { + CloudRoleFolderVo cloudRoleFolderVo = new CloudRoleFolderVo(); + List dataPage = iCloudFileRoleService.getRoleFileCheck(id); + + List ids = dataPage.stream() + .map(CloudRoleFileVo::getFileId) + .collect(Collectors.toList()); + cloudRoleFolderVo.setIds(ids); + + String names = dataPage.stream() + .map(CloudRoleFileVo::getFileName) + .collect(Collectors.joining(", ")); + + String userIDs = dataPage.stream() + .map(CloudRoleFileVo -> String.valueOf(CloudRoleFileVo.getId())) + .collect(Collectors.joining(", ")); + cloudRoleFolderVo.setRoleId(userIDs); + cloudRoleFolderVo.setName(names); + return success("获取数据成功", cloudRoleFolderVo); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + @PostMapping(value = "/changeDeleteStatus/{status}") + @ResponseBody + public BaseResult changeDeleteStatus(@PathVariable String status, String[] ids) { + try { + int[] result = iCloudFileService.changeDeleteStatus(Integer.parseInt(status), ids); + // 没有失败 + if (result[0] != 0 && result[1] == 0) { + return success(200, "修改成功!"); + } + // 有成功的 + else if (result[0] != 0) { + return success(200, result[0] + "个更新成功," + result[1] + "个失败!"); + } else { + return success(500, "修改失败,请重试!"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + + @GetMapping("/queryByIndexPage") + @ResponseBody + public BaseResult queryByIndexPage(Integer page, Integer limit, ReqCloudFile data) { + try { + page=1; + limit=15; + List list = iCloudFileRoleService.getFileRoleByUseId(StpUtil.getLoginIdAsInt()); + + List ids = list.stream() + .map(CloudFileRole::getFileId) + .collect(Collectors.toList()); + data.setFileIds(ids); + + PageList dataPage = iCloudFileService.queryByIndexPage(page, limit, data); + + return success("获取数据成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + + @RequestMapping("authFile") + public String authFile() { + return "cloud/space/file/authFile"; + } + @RequestMapping("updateAuthFile/{id}") + public String updateAuthFile(@PathVariable String id, ModelMap map) { + map.put("id",id); + return "cloud/space/file/updateAuthFile"; + } + @GetMapping("/query") + @ResponseBody + public BaseResult query() { + try { + ReqCloudFile data = new ReqCloudFile(); + List dataPage = iCloudFileService.queryFileByData(data); + List department = buildDepartmentTree(dataPage); + return success(200, "获取数据成功!",department); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + public List buildDepartmentTree(List departments) { + // 1. 按parentId分组 + Map> parentMap = new HashMap<>(); + // 2. 创建所有节点的映射 + Map nodeMap = new HashMap<>(); + // 3. 转换并分组 + for (CloudFileVo dept : departments) { + FileTreeDTO node = new FileTreeDTO(); + org.springframework.beans.BeanUtils.copyProperties(dept, node); + node.setChildren(new ArrayList<>()); + nodeMap.put(dept.getId(), node); + + Long parentId = dept.getFileParentId(); + if (parentId == null) { + parentId = 0L; // 将null转换为0,作为根节点的父ID + } + + parentMap.computeIfAbsent(parentId, k -> new ArrayList<>()) + .add(node); + } + + // 4. 构建树形结构 + List rootList = parentMap.getOrDefault(0L, new ArrayList<>()); + + // 5. 递归构建子节点 + for (Long parentId : parentMap.keySet()) { + if (parentId.equals(0L)) continue; + + FileTreeDTO parentNode = nodeMap.get(parentId); + if (parentNode != null) { + parentNode.setChildren(parentMap.get(parentId)); + } + } + + // 6. 排序(按department_sort) + sortTreeNodes(rootList); + + return rootList; + } + + private void sortTreeNodes(List nodes) { + if (nodes == null || nodes.isEmpty()) return; + + // 按排序字段排序 + nodes.sort(Comparator.comparing(FileTreeDTO::getFileSort)); + + // 递归排序子节点 + for (FileTreeDTO node : nodes) { + if (node.getChildren() != null && !node.getChildren().isEmpty()) { + sortTreeNodes(node.getChildren()); + } + } + } + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/space/CloudFileRoleController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/space/CloudFileRoleController.java new file mode 100644 index 0000000..2542062 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/space/CloudFileRoleController.java @@ -0,0 +1,64 @@ +package com.zxdmy.excite.admin.controller.cloud.space; + + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.entity.cloud.space.CloudFile; +import com.zxdmy.excite.system.entity.cloud.space.CloudFileRole; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFileRole; +import com.zxdmy.excite.system.entity.vo.space.CloudFileRoleVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFilleUserVo; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleUserService; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileRoleService; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileService; +import lombok.AllArgsConstructor; +import org.apache.commons.beanutils.BeanUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

+ * 文件表 前端控制器 + *

+ * + * @author ss + * @since 2026-01-28 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/fileRole") +public class CloudFileRoleController extends BaseController { + + private ICloudFileRoleService iCloudFileRoleService; + + + @GetMapping("/getData") + @ResponseBody + public BaseResult getData(ReqCloudFileRole reqCloudFileRole) { + try { + reqCloudFileRole.setUserId(StpUtil.getLoginIdAsInt()); + CloudFileRole cloudFileRole = iCloudFileRoleService.getData(reqCloudFileRole); + if(null!=cloudFileRole){ + return success("获取数据成功",cloudFileRole); + }else{ + return error(400, "暂无权限!"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/space/CloudRecycleController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/space/CloudRecycleController.java new file mode 100644 index 0000000..98c541f --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/space/CloudRecycleController.java @@ -0,0 +1,80 @@ +package com.zxdmy.excite.admin.controller.cloud.space; + + +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + + +/** + *

+ * 文件表 前端控制器 + *

+ * + * @author ss + * @since 2026-01-28 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/recycle") +public class CloudRecycleController extends BaseController { + + + private ICloudFileService iCloudFileService; + + @RequestMapping("index") + public String index() { + return "cloud/space/recycle/index"; + } + + + @GetMapping("/list") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, ReqCloudFile data) { + try { + PageList dataPage = iCloudFileService.queryByRecyclePage(page, limit, data); + return success("获取数据成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + + @PostMapping("/recover") + @ResponseBody + public BaseResult recover(String id) { + try { + int result = iCloudFileService.recover(id); + if (result == 1) { + return success(200, "恢复成功!"); + }else{ + return error("恢复失败!"); + } + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + @PostMapping("/foreverDelete") + @ResponseBody + @AnnotationSaveReLog + public BaseResult foreverDelete(String id) { + try { + int result = iCloudFileService.deleteById(id); + if (result == 1) { + return success(200, "删除成功!"); + }else{ + return error("删除失败!"); + } + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/trace/CloudTraceController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/trace/CloudTraceController.java new file mode 100644 index 0000000..acec9ac --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/trace/CloudTraceController.java @@ -0,0 +1,73 @@ +package com.zxdmy.excite.admin.controller.cloud.trace; + + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.req.lately.ReqCloudUserLately; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.req.trace.ReqCloudFileTrace; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.entity.vo.trace.CloudFileTraceVo; +import com.zxdmy.excite.system.service.cloud.lately.ICloudUserLatelyService; +import com.zxdmy.excite.system.service.cloud.trace.ICloudFileTraceService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + *

+ * 最近文件表 前端控制器 + *

+ * + * @author 沈松 + * @since 2026-01-29 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/trace") +public class CloudTraceController extends BaseController { + + private ICloudFileTraceService iCloudFileTraceService; + + @RequestMapping("index") + public String index() { + return "cloud/lately/index"; + } + + + @GetMapping("/list") + @ResponseBody + public BaseResult getPageList(Integer page, Integer limit, ReqCloudFileTrace data) { + try { + page = 1; + limit = 15; + PageList dataPage = iCloudFileTraceService.queryByPage(page, limit, data); + return success("获取列表成功", dataPage.getList(), (int) dataPage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @PostMapping("/addSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult addSave(@Validated ReqCloudFileTrace data) { + try { + if(iCloudFileTraceService.saveData(data)==1){ + return success("操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/upload/UploadController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/upload/UploadController.java new file mode 100644 index 0000000..b583314 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/cloud/upload/UploadController.java @@ -0,0 +1,90 @@ +package com.zxdmy.excite.admin.controller.cloud.upload; + +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.cloud.space.CloudFile; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileService; +import lombok.AllArgsConstructor; +import org.apache.commons.beanutils.BeanUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.lang.reflect.InvocationTargetException; + +/** + * 系统菜单/权限表 前端控制器 + * + * @author 沈松 + * @since 2021-09-12 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/upload/") +public class UploadController extends BaseController { + + private ICloudFileService iCloudFileService; + + + @RequestMapping("index/{id}") + public String index(@PathVariable String id, ModelMap map) throws InvocationTargetException, IllegalAccessException { + map.put("id", id); + return "cloud/upload/index"; + } + @PostMapping("/addSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult addSave(@Validated ReqCloudFile data) { + try { + String oldName = data.getFileName(); + if(null!=data.getFileName()){ + String[] file = data.getFileName().split("\\."); + if(file.length>0) { + data.setFileName(file[0].toString()); + } + } + + if(null == iCloudFileService.getByData(data)){ + data.setFileName(oldName); + if(iCloudFileService.saveFileData(data)==1){ + return success("操作成功"); + }else{ + return error(400, "操作失败,系统错误"); + } + }else{ + return error(400, "操作失败,数据已存在"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @PostMapping("/editSave") + @ResponseBody + @AnnotationSaveReLog + public BaseResult editSave(@Validated ReqCloudFile data) { + try { + + if(iCloudFileService.updateFileData(data)==1){ + return success("操作成功"); + }else{ + return error(400, "操作失败,数据已存在"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @RequestMapping("changeIndex/{id}") + public String changeIndex(@PathVariable String id, ModelMap map) throws InvocationTargetException, IllegalAccessException { + map.put("id", id); + return "cloud/upload/changeIndex"; + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/component/AlipayController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/component/AlipayController.java new file mode 100644 index 0000000..8db3293 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/component/AlipayController.java @@ -0,0 +1,83 @@ +package com.zxdmy.excite.admin.controller.component; + +import cn.hutool.core.util.IdUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.component.alipay.AlipayService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + *

+ * 描述 + *

+ * + * @author 沈松 + * @since 2022/1/11 20:45 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/component/alipay") +public class AlipayController extends BaseController { + + AlipayService alipayService; + + @RequestMapping("index") + public String index() { + return "component/alipay/index"; + } + + + @PostMapping(value = "/pay") + @ResponseBody + public BaseResult pay(String title, String price) { + String outTradeNo = IdUtil.simpleUUID(); + String qrcode = alipayService.pay(null, "facetoface", title, outTradeNo, price, null, null); + + return success(200, "获取支付二维码成功!") + .put("qrcode", qrcode) + .put("outTradeNo", outTradeNo); + } + + @GetMapping(value = "/page") + @ResponseBody + public String page(String title, String price,String returnUrl) { + String outTradeNo = IdUtil.simpleUUID(); + String qrcode = alipayService.pay(null, "page", title, outTradeNo, price, returnUrl, null); + return qrcode; +// return success(200, "获取支付二维码成功!") +// .put("qrcode", qrcode) +// .put("outTradeNo", outTradeNo); + } + + @PostMapping(value = "/refund") + @ResponseBody + public BaseResult refund(String outTradeNo, String amount) { + String[] result = alipayService.refund(null, null, outTradeNo, amount, "用户取消退款"); + if ("Y".equals(result[0])) { + return success(200, "退款成功,退款金额:" + result[4]); + } else if ("N".equals(result[0])) { + return success(200, "该订单早已退款成功!退款金额:" + result[4]); + } else + return error("退款错误:" + result[1] + result[2]); + } + + @PostMapping(value = "/query") + @ResponseBody + public BaseResult query(String outTradeNo) { + String[] result = alipayService.queryPay(null, null, outTradeNo); + if ("Y".equals(result[0])) { + return success(200, "查询成功!" + + " 支付宝交易号:" + result[1] + + " 交易状态:" + result[3] + + " 订单金额:" + result[4] + + " 买家账号:" + result[6]); + } + return error("查询失败:" + result[1] + result[2]); + } + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/component/QiniuOssController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/component/QiniuOssController.java new file mode 100644 index 0000000..613dece --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/component/QiniuOssController.java @@ -0,0 +1,43 @@ +package com.zxdmy.excite.admin.controller.component; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.qiniu.storage.model.FileInfo; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.component.qiniu.QiniuOssService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.List; + +/** + * 七牛云文件存储服务控制类 + * + * @author 沈松 + * @since 2022/1/24 21:49 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/component/qiniuOss") +public class QiniuOssController extends BaseController { + + QiniuOssService qiniuOssService; + + @RequestMapping("index") + public String index() { + return "component/qiniuOss/index"; + } + + @GetMapping(value = "/fileList") + @ResponseBody + public BaseResult getList(Integer page, Integer limit) { + Page fileInfoList = qiniuOssService.getQiniuFileListPage(page, limit, "", ""); + return success("获取成功!", fileInfoList.getRecords(), (int) fileInfoList.getTotal()); + } + + + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/component/WeChatPayController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/component/WeChatPayController.java new file mode 100644 index 0000000..dda77a9 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/component/WeChatPayController.java @@ -0,0 +1,92 @@ +package com.zxdmy.excite.admin.controller.component; + +import cn.hutool.core.util.IdUtil; +import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result; +import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.component.wechat.WeChatPayService; +import lombok.AllArgsConstructor; +import org.aspectj.weaver.ast.Or; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.Timer; + +/** + *

+ * 描述 + *

+ * + * @author 沈松 + * @since 2022/1/11 20:45 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/component/wechatPay") +public class WeChatPayController extends BaseController { + + WeChatPayService weChatPayService; + + + @RequestMapping("index") + public String requestLogPage() { + return "component/wechatPay/index"; + } + + @PostMapping(value = "/pay") + @ResponseBody + public BaseResult pay(String title, Float price) { + System.out.println(title); + System.out.println(price); + int total = (int) (price * 100); + String outTradeNo = IdUtil.simpleUUID(); + String result = weChatPayService.pay(null, "native", title, outTradeNo, total, null); + + return success(200, "获取支付二维码成功!") + .put("qrcode", result) + .put("outTradeNo", outTradeNo); + } + + @PostMapping(value = "/refund") + @ResponseBody + public BaseResult refund(String outTradeNo, Float amount) { + int refund = (int) (amount * 100); + // 查询该订单的实际支付金额 + int total = weChatPayService.query(null, null, outTradeNo).getAmount().getTotal(); + if (refund > total) { + return error("退款金额大于支付金额!"); + } + WxPayRefundV3Result wxPayRefundV3Result = weChatPayService.refund(null, outTradeNo, IdUtil.simpleUUID(), total, refund); + if ("SUCCESS".equals(wxPayRefundV3Result.getStatus())) { + return success(200, "退款成功!"); + } else if ("PROCESSING".equals(wxPayRefundV3Result.getStatus())) { + return success(200, "退款处理中...稍后到账,请注意查收微信通知!"); + } + return error("退款失败!"); + } + + @PostMapping(value = "/query") + @ResponseBody + public BaseResult query(String outTradeNo) { + WxPayOrderQueryV3Result wxPayOrderQueryV3Result = weChatPayService.query(null, null, outTradeNo); + if (wxPayOrderQueryV3Result.getTradeState().equals("SUCCESS")) { + return success(200, "支付成功!,交易成功时间:" + wxPayOrderQueryV3Result.getSuccessTime()); + } else if (wxPayOrderQueryV3Result.getTradeState().equals("NOTPAY")) { + return error("未支付!"); + } else if (wxPayOrderQueryV3Result.getTradeState().equals("CLOSED")) { + return error("订单已关闭!"); + } else if (wxPayOrderQueryV3Result.getTradeState().equals("USERPAYING")) { + return success(200, "用户支付中(付款码支付)!"); + } else if (wxPayOrderQueryV3Result.getTradeState().equals("PAYERROR")) { + return error("支付失败(其他原因,如银行返回失败)!"); + } else if (wxPayOrderQueryV3Result.getTradeState().equals("REFUND")) { + return error("订单已退款!"); + } else + return error(wxPayOrderQueryV3Result.getTradeState() + ":订单不存在"); + } + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/fileSet/PDFController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/fileSet/PDFController.java new file mode 100644 index 0000000..155d47f --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/fileSet/PDFController.java @@ -0,0 +1,42 @@ +package com.zxdmy.excite.admin.controller.fileSet; + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.SysMenu; +import com.zxdmy.excite.system.service.ISysMenuService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * 系统菜单/权限表 前端控制器 + * + * @author 沈松 + * @since 2021-09-12 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/pdf/") +public class PDFController extends BaseController { + + private ISysMenuService menuService; + + /** + * @return 页面:【菜单管理】页面入口 + */ + @RequestMapping("index") + public String index() { + return "file/pdf"; + } + + + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/oss/OssController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/oss/OssController.java new file mode 100644 index 0000000..7d30a9d --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/oss/OssController.java @@ -0,0 +1,133 @@ +package com.zxdmy.excite.admin.controller.oss; + +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.model.MatchMode; +import com.aliyun.oss.model.PolicyConditions; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.component.oss.AliOSSProperties; +import lombok.AllArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.time.LocalDate; +import java.util.*; + +/** + * 系统菜单/权限表 前端控制器 + * + * @author 沈松 + * @since 2021-09-12 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/cloud/oss/") +public class OssController extends BaseController { + + @Autowired//将OSS的配置注入进来,后面需要用到 + + private AliOSSProperties aliOSSProperties; + + + /** + * 获取OSS上传凭证(用于前端直传) + */ + + + @GetMapping("/policy") + @ResponseBody + public BaseResult getUploadPolicy() { + try { + // 使用简化版本的Policy生成 + Map policy = getSimpleUploadPolicy(); + return success("获取列表成功", policy); + } catch (Exception e) { + return error("获取上传凭证失败: " + e.getMessage()); + } + } + + + + + /** + * 生成唯一的文件名 + */ + private String generateFileName(String originalFilename) { + String suffix = ""; + if (originalFilename != null && originalFilename.contains(".")) { + suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); + } + return UUID.randomUUID().toString().replace("-", "") + suffix; + } + /** + * 简化的Policy获取方法 + */ + public Map getSimpleUploadPolicy() { + Map result = new HashMap<>(); + + try { + // 生成目录:按年月 + String dir = "cloud/" + + LocalDate.now().getYear() + "-" + + String.format("%02d", LocalDate.now().getMonthValue()); + + // 确保以/结尾 + if (!dir.endsWith("/")) { + dir = dir + "/"; + } + + // 使用更简单的key格式:cloud/2026-01/${filename} + String key = dir + "${filename}"; + + // Policy过期时间 + long expireEndTime = System.currentTimeMillis() + 300 * 1000; + Date expiration = new Date(expireEndTime); + + // 创建Policy + PolicyConditions policyConds = new PolicyConditions(); + policyConds.addConditionItem( + PolicyConditions.COND_CONTENT_LENGTH_RANGE, + 0, + 1048576000 + ); + + // 使用starts-with条件,允许任意文件名 + policyConds.addConditionItem( + MatchMode.StartWith, + PolicyConditions.COND_KEY, + dir + ); + + String endpoint = aliOSSProperties.getEndpoint(); + String accessKeyId = aliOSSProperties.getAccessKeyId(); + String accessKeySecret = aliOSSProperties.getAccessKeySecret(); + String bucketName = aliOSSProperties.getBucketName(); + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret); + + String postPolicy = ossClient.generatePostPolicy(expiration, policyConds); + String encodedPolicy = Base64.getEncoder().encodeToString(postPolicy.getBytes("UTF-8")); + String signature = ossClient.calculatePostSignature(postPolicy); + + // 返回结果 + result.put("OSSAccessKeyId", accessKeyId); + result.put("policy", encodedPolicy); + result.put("signature", signature); + result.put("key", key); // 这个key必须包含${filename} + result.put("host", "https://" + bucketName + "." + endpoint); + result.put("dir", dir); + result.put("expire", String.valueOf(expireEndTime / 1000)); + result.put("success_action_status", "200"); + + + + } catch (Exception e) { + throw new RuntimeException("生成上传凭证失败", e); + } + + return result; + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/CloudRoleFileController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/CloudRoleFileController.java new file mode 100644 index 0000000..3936b27 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/CloudRoleFileController.java @@ -0,0 +1,21 @@ +package com.zxdmy.excite.admin.controller.system; + + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.stereotype.Controller; +import com.zxdmy.excite.common.base.BaseController; + +/** + *

+ * 云盘权限文件表 前端控制器 + *

+ * + * @author 沈松 + * @since 2026-02-01 + */ +@Controller +@RequestMapping("/cloud-role-file") +public class CloudRoleFileController extends BaseController { + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/CloudUserCollectionController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/CloudUserCollectionController.java new file mode 100644 index 0000000..e361a22 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/CloudUserCollectionController.java @@ -0,0 +1,21 @@ +package com.zxdmy.excite.admin.controller.system; + + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.stereotype.Controller; +import com.zxdmy.excite.common.base.BaseController; + +/** + *

+ * 收藏表 前端控制器 + *

+ * + * @author 沈松 + * @since 2026-01-29 + */ +@Controller +@RequestMapping("/cloud-user-collection") +public class CloudUserCollectionController extends BaseController { + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysController.java new file mode 100644 index 0000000..8f67a8a --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysController.java @@ -0,0 +1,77 @@ +package com.zxdmy.excite.admin.controller.system; + + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.component.qiniu.QiniuOssService; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.service.ISysUserService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * 系统模块基础控制器 + * + * @author 沈松 + * @since 2021-09-30 0030 23:45 + */ +@Controller +@AllArgsConstructor +public class SysController extends BaseController { + + ISysUserService userService; + + /** + * 开发模式下:默认访问域名,跳转至后台主页 + * 如果后期有新的首页,删除即可 + * + * @return 页面跳转 + */ + @RequestMapping("") + public String defaultPage() { + return "redirect:/system/login"; + } + + /** + * @return 【后台主页】访问入口 + */ + @RequestMapping("system/index") + public String index(ModelMap map) { + // 已登录,访问后台主页 + if (StpUtil.isLogin()) { + SysUser user = userService.getById(StpUtil.getLoginIdAsInt()); + map.put("user", user); + return "system/index"; + } + // 未登录,跳转至登录页面 + return "redirect:/system/login"; + } + + /** + * @return 【登录】页面入口 + */ + @RequestMapping("system/login") + public String login() { + // 已登录:跳转至后台首页 + if (StpUtil.isLogin()) { + return "redirect:/system/index"; + } + // 未登录,跳转至登录页面 + return "system/login"; + } + + /** + * @return 后台欢迎页面访问入口 + */ + @RequestMapping("system/welcome") + public String welcome() { + return "system/welcome"; + } + + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysLogController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysLogController.java new file mode 100644 index 0000000..1487fcb --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysLogController.java @@ -0,0 +1,119 @@ +package com.zxdmy.excite.admin.controller.system; + + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.system.entity.SysLogLogin; +import com.zxdmy.excite.system.entity.SysLogRequest; +import com.zxdmy.excite.system.entity.SysMenu; +import com.zxdmy.excite.system.service.ISysLogLoginService; +import com.zxdmy.excite.system.service.ISysLogRequestService; +import lombok.AllArgsConstructor; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.*; + +import org.springframework.stereotype.Controller; +import com.zxdmy.excite.common.base.BaseController; + +import java.time.LocalDateTime; + +/** + * 日志管理控制器 + * + * @author 沈松 + * @since 2021-12-09 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/system/log") +public class SysLogController extends BaseController { + + ISysLogRequestService logRequestService; + + ISysLogLoginService logLoginService; + + /** + * @return 【操作日志】页面访问入口 + */ + @RequestMapping("request") + public String requestLogPage() { + return "system/log/request"; + } + + /** + * @return 【登录日志】页面访问入口 + */ + @RequestMapping("login") + public String loginLogPage() { + return "system/log/login"; + } + + + /** + * 获取操作日志列表(含查询条件) + * + * @param page 页码 + * @param limit 页条数 + * @param userId 用户ID,格式:10001 + * @param startDate 开始时间,格式:2022-01-11 00:00:00 + * @param endDate 结束时间,格式:2022-01-11 00:00:00 + * @return 操作日志列表 + */ + @GetMapping("/requestList") + @ResponseBody + public BaseResult requestList(Integer page, Integer limit, String userId, String startDate, String endDate) { + try { + // TODO 加上根据ID和开始、结束时间的搜索功能 + Page rolePage = logRequestService.getPage(page, limit, userId, startDate, endDate); + return success("获取日志列表成功", rolePage.getRecords(), (int) rolePage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + /** + * 获取登录日志列表 + * + * @param page 页码 + * @param limit 页条数 + * @param userId 用户ID,格式:10001 + * @param startDate 开始时间,格式:2022-01-11 00:00:00 + * @param endDate 结束时间,格式:2022-01-11 00:00:00 + * @return 登录日志列表 + */ + @GetMapping("/loginList") + @ResponseBody + public BaseResult loginList(Integer page, Integer limit, String userId, String ip, String startDate, String endDate) { + try { + // TODO 加上搜索功能,详情同上 + Page rolePage = logLoginService.getPage(page, limit, userId, ip, startDate, endDate); + return success("获取日志列表成功", rolePage.getRecords(), (int) rolePage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + @PostMapping("/request/delete") + @ResponseBody + public BaseResult deleteRequestLog(Integer[] logIds) { + if (null == logIds || logIds.length == 0) { + return error("请求数据为空!"); + } + if (logRequestService.deleteLog(logIds) > 0) { + return success("删除成功!"); + } + return error("删除失败!"); + } + + @PostMapping("/login/delete") + @ResponseBody + public BaseResult deleteLoginLog(Integer[] logIds) { + if (null == logIds || logIds.length == 0) { + return error("请求数据为空!"); + } + if (logLoginService.deleteLog(logIds) > 0) { + return success("删除成功!"); + } + return error("删除失败!"); + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysMenuController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysMenuController.java new file mode 100644 index 0000000..298cf1b --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysMenuController.java @@ -0,0 +1,334 @@ +package com.zxdmy.excite.admin.controller.system; + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.SysMenu; +import com.zxdmy.excite.system.service.ISysMenuService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 系统菜单/权限表 前端控制器 + * + * @author 沈松 + * @since 2021-09-12 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/system/menu") +public class SysMenuController extends BaseController { + + private ISysMenuService menuService; + + /** + * @return 页面:【菜单管理】页面入口 + */ + @RequestMapping("index") + public String index() { + return "system/menu/index"; + } + + /** + * @return 页面:【菜单管理-添加菜单】页面入口 + */ + @RequestMapping("goAdd") + public String goAdd() { + return "system/menu/add"; + } + + /** + * 页面:【菜单管理-编辑菜单】页面入口 + * + * @param id 菜单ID + * @param map Map + * @return 【菜单管理-编辑菜单】页面入口 + */ + @RequestMapping("goEdit/{id}") + public String goEdit(@PathVariable String id, ModelMap map) { + try { + // 尝试获取菜单信息,并返回前端 + SysMenu menu = menuService.getMenu(Integer.parseInt(id)); + if (null != menu) { + // 此处是为了适应前端的图标选择器,将"fa "截掉 + if ("".equals(menu.getIcon()) && null != menu.getIcon()) { + menu.setIcon(menu.getIcon().substring(3)); + } + map.put("menu", menu); + return "system/menu/edit"; + } else { + return "error/404"; + } + } catch (Exception e) { + // 发生异常,一般就是数字转换出错 + System.err.println(e.getMessage()); + return "error/500"; + } + } + + /** + * 接口功能:菜单管理-添加菜单 接口 + * + * @param menu 菜单信息 + * @return 菜单添加结果 + */ + @PostMapping("/add") + @ResponseBody + @AnnotationSaveReLog + public BaseResult addMenu(@Validated SysMenu menu) { + // 添加菜单 + if (menuService.saveMenu(menu) > 0) { + return success("菜单添加成功"); + } + return error(400, "菜单添加失败"); + } + + /** + * 接口功能:根据菜单ID查询菜单并返回结果 + * + * @param id 菜单ID + * @return 查询结果 + */ + @GetMapping("/get/{id}") + @ResponseBody + public BaseResult getMenu(@PathVariable String id) { + try { + SysMenu menu = menuService.getMenu(Integer.parseInt(id)); + if (null != menu) { + return success("获取菜单成功", menu); + } + return error(400, "获取菜单失败"); + } catch (Exception e) { + return error(400, "发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:查询菜单列表,并组合后台首页的其他信息 + * + * @return 菜单列表,以及后台标题等信息 + */ + @GetMapping("/indexList") + @ResponseBody + public BaseResult getMenuListIndex() { + List menus = menuService.getMenuListByUserId(StpUtil.getLoginIdAsInt(), true); + if (null != menus) { + // 如果是【tree】,则需要将菜单初始化成树状结构 + menus = this.initMenu(menus); + // 首页信息 + HashMap map = new HashMap<>(); + map.put("title", "首页"); + map.put("href", "/system/welcome"); + // logo信息 + HashMap map2 = new HashMap<>(); + map2.put("title", ""); + map2.put("image", "/images/logo/logo.png"); + map2.put("href", "/system/index"); + // 转换成相应的格式 + return success("获取菜单成功").put("homeInfo", map).put("logoInfo", map2).put("menuInfo", menus); + } + return error(400, "获取菜单失败"); + } + + /** + * 接口功能:根据类型获取菜单列表 + * + * @param type all:查询全部数据 | menu:查询除了按钮的全部数据 | tree:查询树状菜单(不含按钮) + * @return 菜单/权限列表 + */ + @GetMapping("/list/{type}") + @ResponseBody + public BaseResult getMenuList(@PathVariable String type) { + boolean isAll = "all".equals(type); + boolean isTree = "tree".equals(type); + List menus = menuService.getMenuList(isAll); + if (null != menus) { + // 如果是【tree】,则需要将菜单初始化成树状结构 + if (isTree) { + menus = this.initMenu(menus); + return success("获取菜单成功", menus); + } + return success("获取菜单成功", menus, menus.size()); + } + return error(400, "获取菜单失败"); + } + + /** + * 接口功能:获取菜单列表,其中该角色拥有的菜单的checkArr字段为"1" + * + * @param roleId 角色ID。0表示获取所有的状态正常的菜单 + * @return 全部角色列表,其中指定角色拥有的菜单的checkArr字段为"1" + */ + @GetMapping("/listForRole/{roleId}") + @ResponseBody + public BaseResult getMenuListForRole(@PathVariable String roleId) { + try { + List menus = menuService.getMenuListForRole(Integer.parseInt(roleId)); + if (null != menus) { + return success("获取菜单列表成功", menus); + } + return error(400, "获取菜单失败"); + } catch (Exception e) { + return error(400, "发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:根据角色ID获取菜单/权限 + * + * @param roleId 角色ID + * @return 该角色具有的菜单/权限列表 + */ + @GetMapping("/listByRoleId/{roleId}") + @ResponseBody + public BaseResult getMenuListByRoleId(@PathVariable String roleId) { + try { + List menus = menuService.getMenuListByRoleId(Integer.parseInt(roleId)); + return success("角色[" + roleId + "]拥有的菜单获取成功!", menus, menus.size()); + } catch (Exception e) { + return error(400, "error:" + e.getMessage()); + } + } + + /** + * 接口功能:根据用户ID获取菜单/权限 + * + * @param userId 用户ID + * @return 该用户具有的菜单/权限列表 + */ + @GetMapping("/listByUserId/{userId}") + @ResponseBody + public BaseResult getMenuListByUserId(@PathVariable String userId) { + try { + List menus = menuService.getMenuListByUserId(Integer.parseInt(userId), false); + return success("用户[" + userId + "]拥有的菜单获取成功!", menus, menus.size()); + } catch (Exception e) { + return error(400, "发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:更新菜单 + * + * @param menu 菜单实体 + * @return 菜单更新结果 + */ + @PostMapping("/update") + @ResponseBody + @AnnotationSaveReLog + public BaseResult updateMenu(@Validated SysMenu menu) { + // 执行修改菜单操作 + if (menuService.saveMenu(menu) > 0) { + return success("更新菜单成功"); + } + return error(400, "更新菜单失败"); + } + + + /** + * 接口功能:根据ID修改菜单状态 + * + * @param status 菜单新状态:1-正常 0-禁用 + * @param menuIds 需要修改状态的菜单ID数组 + * @return 菜单状态修改结果 + */ + @PostMapping("/changeStatus/{status}") + @ResponseBody + @AnnotationSaveReLog + public BaseResult changeMenuStatus(@PathVariable String status, Integer[] menuIds) { + try { + int[] result = menuService.changeStatus(Integer.parseInt(status), menuIds); + if (result[0] > 0) { + return success(result[0] + "个菜单状态更新成功," + result[1] + "个失败。"); + } + return error(400, "菜单状态更新失败!"); + } catch (Exception e) { + return error(400, "error:" + e.getMessage()); + } + } + + /** + * 接口功能:根据ID删除菜单 + * + * @param id 菜单ID + * @return 删除结果 + */ + @PostMapping("/remove") + @ResponseBody + @AnnotationSaveReLog + public BaseResult removeMenu(String id) { + try { + if (menuService.deleteMenu(Integer.parseInt(id)) > 0) { + return success("菜单删除成功"); + } + return error(400, "菜单删除失败"); + } catch (Exception e) { + return error(400, "发生错误:" + e.getMessage()); + } + } + + + /** + * 【注意:正常来说,这种工具应该以工具类的形式定义。但本项目中,我们只在此控制类中使用一次,所以就写在各个文件中】 + *

+ * 构造菜单树状列表数据 + * + * @param menuList 查询到的菜单列表 + * @return 合并后的树状列表 + */ + private List initMenu(List menuList) { + // 如果菜单为空,直接返回空 + if (menuList.isEmpty()) { + return null; + } + // 定义新的菜单列表,用来返回 + List retMenuList = new ArrayList<>(); + // 循环遍历:查找顶级菜单(有的项目中是顶部导航菜单) + for (SysMenu aMenuList : menuList) { + // 顶级菜单的特征是父级ID为 -1 + if (null != aMenuList.getParentId() && -1 == aMenuList.getParentId()) { + retMenuList.add(aMenuList); + } + } + //遍历所有菜单,将二级菜单添加至对应的一级菜单内 + for (SysMenu menu : retMenuList) { + menu.setChild(getChild(menu.getId(), menuList)); + } + //返回构建后的树状菜单 + return retMenuList; + } + + /** + * 设置子菜单(递归调用) + * + * @param parentId 父级菜单ID + * @param menuList 全部菜单列表 + * @return 子菜单结果集合 + */ + private List getChild(Integer parentId, List menuList) { + List result = new ArrayList<>(); + // 遍历,将子菜单添加进父菜单项内 + for (SysMenu menu : menuList) { + if (null != menu.getParentId() && parentId.equals(menu.getParentId())) { + result.add(menu); + } + } + // 继续遍历二级菜单是否有子菜单(递归) + for (SysMenu menu : result) { + menu.setChild(getChild(menu.getId(), menuList)); + } + //递归终止条件 + if (result.size() == 0) { + return null; + } + //返回结果集 + return result; + } + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysRoleController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysRoleController.java new file mode 100644 index 0000000..a084510 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysRoleController.java @@ -0,0 +1,282 @@ +package com.zxdmy.excite.admin.controller.system; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.SysRole; +import com.zxdmy.excite.system.service.ISysRoleService; +import com.zxdmy.excite.system.service.ISysUserRoleService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * 系统角色表 前端控制器 + * + * @author 沈松 + * @since 2021-09-23 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/system/role") +public class SysRoleController extends BaseController { + + ISysRoleService roleService; + + ISysUserRoleService userRoleService; + + /** + * @return 页面:【角色管理】页面入口 + */ + @RequestMapping("index") + public String index() { + return "system/role/index"; + } + + /** + * @return 页面:【角色管理-添加角色】页面入口 + */ + @RequestMapping("goAdd") + public String goAdd() { + return "system/role/add"; + } + + /** + * @param id 角色ID + * @param map map + * @return 页面:【角色管理-编辑角色】页面入口 + */ + @RequestMapping("goEdit/{id}") + public String goEdit(@PathVariable String id, ModelMap map) { + try { + SysRole role = roleService.getRole(Integer.parseInt(id)); + if (null != role) { + map.put("role", role); + return "system/role/edit"; + } else { + map.put("code", 500); + map.put("msg", "可能原因:该角色禁止编辑,该角色已被禁用!"); + return "error/error"; + } + } catch (Exception e) { + // 发生异常,一般就是数字转换出错 + System.err.println(e.getMessage()); + return "error/500"; + } + } + + @RequestMapping("goShowUser/{id}") + public String showUser(@PathVariable String id, ModelMap map) { + try { + SysRole role = roleService.getRole(Integer.parseInt(id)); + if (null == role) { + map.put("code", 500); + map.put("msg", "可能原因:该角色禁止编辑,该角色已被禁用!"); + return "error/error"; + } else { + map.put("role", role); + return "system/role/authUser"; + } + } catch (Exception e) { + // 发生异常,一般就是数字转换出错 + System.err.println(e.getMessage()); + return "error/500"; + } + } + + /** + * 接口功能:添加角色,并支持同时分配权限 + * + * @param role 角色实体 + * @param menuIds 该角色拥有的菜单ID,数组类型:[1,2,3,4,5,6],前端传递字符串格式:1,2,3,4 + * @return 添加结果 + */ + @PostMapping("/add") + @ResponseBody + @AnnotationSaveReLog + public BaseResult addRole(@Validated SysRole role, Integer[] menuIds) { + try { + if (roleService.saveRole(role, menuIds) > 0) { + return success("菜单角色成功"); + } + return error(400, "菜单角色失败"); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:通过角色ID获取角色信息 + * + * @param id 角色ID + * @return 指定角色的信息 + */ + @GetMapping("/get/{id}") + @ResponseBody + @AnnotationSaveReLog + public BaseResult getRole(@PathVariable String id) { + try { + SysRole role = roleService.getRole(Integer.parseInt(id)); + if (null != role) { + return success("获取角色成功", role); + } + return error(400, "获取角色失败"); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:获取所有角色,支持条件搜索 + * + * @param page 页号 + * @param limit 当前页数目 + * @param name 搜索字段:名称 + * @param permission 搜索字段:权限字符 + * @return 符合要求的角色列表 + */ + @GetMapping("/list") + @ResponseBody + public BaseResult getRoleList(Integer page, Integer limit, String name, String permission) { + try { + Page rolePage = roleService.getPage(page, limit, name, permission); + return success("获取角色列表成功", rolePage.getRecords(), (int) rolePage.getTotal()); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:获取获取所有正常的角色,为用户模块所用(添加、编辑用户) + * 其中:如果指定ID(即ID不为0),则该用户的角色列表中,已分配的角色属性中的checkArr=1 + * + * @param userId 用户ID。如果为0,则表示获取所有列表 + * @return JSON结果 + */ + @GetMapping("/listForUser/{userId}") + @ResponseBody + public BaseResult getRoleListForUser(@PathVariable String userId) { + try { + List roleList = roleService.getListByUserId(Integer.parseInt(userId)); + return success("获取角色列表成功", roleList, roleList.size()); + } catch (Exception e) { + return error(500, "error:" + e.getMessage()); + } + } + + /** + * 接口功能:更新角色接口 + * + * @param role 角色实体 + * @param menuIds 该角色拥有的菜单ID,数组类型:[1,2,3,4,5,6],前端发送数据格式为字符串:1,2,3,4 + * @return 结果 + */ + @PostMapping("/update") + @ResponseBody + @AnnotationSaveReLog + public BaseResult updateRole(@Validated SysRole role, Integer[] menuIds) { + try { + if (roleService.saveRole(role, menuIds) > 0) { + return success("更新角色成功"); + } + return error(400, "更新角色失败,请重试"); + } catch (Exception e) { + return error(500, "error:" + e.getMessage()); + } + } + + /** + * 接口功能:更新角色状态 + * + * @param status 角色新状态:1-正常 0-禁用 + * @param roleIds 角色ID列表,数组类型:[1,2,3,4,5,6] + * @return 修改结果 + */ + @PostMapping("/changeStatus/{status}") + @ResponseBody + @AnnotationSaveReLog + public BaseResult changeStatus(@PathVariable String status, Integer[] roleIds) { + try { + int[] result = roleService.changeStatus(Integer.parseInt(status), roleIds); + if (result[0] > 0) { + return success(result[0] + "个角色状态更新成功," + result[1] + "个失败!"); + } else + return error(400, "更新角色状态失败,请重试"); + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:删除指定角色,包含该角色的权限信息,以及撤销分配给某些用户的角色 + * + * @param roleIds 要删除的角色ID列表 + * @return 结果 + */ + @PostMapping("/delete") + @ResponseBody + @AnnotationSaveReLog + public BaseResult removeRole(Integer[] roleIds) { + try { + int[] result = roleService.deleteRoleById(roleIds); + // 没有失败的 + if (result[1] == 0 && result[2] == 0) { + return success(200, "删除成功!"); + } + // 没有成功的 + else if (result[0] == 0) { + return error(result[1] + "个角色删除失败!" + result[2] + "个角色因已授权用户,请取消授权后再删除!"); + } + // 有成功有失败的 + else { + return success(200, result[0] + "个角色删除成功!" + result[1] + "个角色删除失败!" + result[2] + "个角色已授权用户,请取消授权后再删除!"); + } + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:将指定角色分配给系列用户,或者取消某角色分配给的用户 + * + * @param type 操作类型:auth-添加授权 | revoke-取消授权 + * @param roleId 用户ID + * @param userIds 角色信息列表 + * @return 分配结果 + */ + @PostMapping("/authUser/{type}") + @ResponseBody + @AnnotationSaveReLog + public BaseResult authForUser(@PathVariable("type") String type, String roleId, Integer[] userIds) { + try { + // 添加授权 + if (type.equals("auth")) { + if (roleService.authRoleForUsers(Integer.parseInt(roleId), userIds)) + return success(200, "添加授权成功!"); + else + return error("授权失败,请重试!"); + } + // 取消授权 + else if (type.equals("revoke")) { + int[] result = roleService.revokeRoleForUsers(Integer.parseInt(roleId), userIds); + if (result[1] == 0) + return success(200, "取消授权成功!"); + else if (result[0] == 0) + return error("取消授权失败,请重试!"); + else + return success(result[0] + "个用户取消授权成功," + result[1] + "个失败!"); + } + return error("访问错误!"); + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysUserController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysUserController.java new file mode 100644 index 0000000..18b7acc --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/system/SysUserController.java @@ -0,0 +1,456 @@ +package com.zxdmy.excite.admin.controller.system; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.SaTokenInfo; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; + +import com.zxdmy.excite.common.config.ExciteConfig; +import com.zxdmy.excite.common.enums.ReturnCode; +import com.zxdmy.excite.common.enums.SystemCode; +import com.zxdmy.excite.common.service.RedisService; +import com.zxdmy.excite.framework.aop.AnnotationSaveLoginLog; +import com.zxdmy.excite.framework.aop.AnnotationSaveReLog; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.service.ISysUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpSession; +import java.util.Arrays; +import java.util.List; + +/** + * 系统用户表 前端控制器 + * + * @author 沈松 + * @since 2021-09-01 + */ +@Tag(name = "后台用户控制器") +@Controller +@AllArgsConstructor +@RequestMapping("/system/user") +public class SysUserController extends BaseController { + + private ISysUserService userService; + +// private RedisService redisUtils; + + private ExciteConfig exciteConfig; + + /** + * 访问页面:用户管理 - 列表页面 + * + * @return 跳转至列表页面 + */ + @RequestMapping("index") + public String index() { + return "system/user/index"; + } + + /** + * 访问页面:用户管理 - 添加用户页面 + * + * @return 跳转至添加用户页面 + */ + @RequestMapping("goAdd") + public String goAdd() { + return "system/user/add"; + } + + /** + * 访问页面:用户管理 - 编辑用户信息页面 + * + * @return 跳转至编辑用户页面 + */ + @RequestMapping("goEdit/{id}") + public String goEdit(@PathVariable String id, ModelMap map) { + // 获取该用户的信息 + SysUser user = userService.getById(id); + // 加载至前端 + if (user == null) { + map.put("code", 404); + map.put("msg", "用户不存在!"); + return "error/error"; + } + map.put("user", user); + return "system/user/edit"; + } + + /** + * 访问页面:用户管理 - 为用户分配角色页面 + * + * @return 跳转至编辑用户页面 + */ + @RequestMapping("goAuthRole/{id}") + public String goAuthRole(@PathVariable String id, ModelMap map) { + // 获取该用户的信息 + SysUser user = userService.getById(id); + // 加载至前端 + if (user == null) { + map.put("code", 404); + map.put("msg", "用户不存在!"); + return "error/error"; + } + map.put("user", user); + return "system/user/authRole"; + } + + + /** + * 接口功能:用户登录 + * 基本逻辑:校验前端信息-->校验验证码-->校验用户名、密码-->登录 + * + * @param username 用户名 + * @param password 密码 + * @param captcha 验证码 + * @param remember 是否记住登录状态 1-记住 | 0-不记住(记住登录状态后,关闭浏览器,不退出。不记住登录状态,关闭浏览器后即退出登录。只有手动退出才可以) + * @return JSON:登录结果 + */ + @PostMapping(value = "/login") + @ResponseBody + @AnnotationSaveLoginLog + public BaseResult login(String username, String password,String remember) { + // 如果提交的信息有空信息 + if (StrUtil.hasBlank(username, password)) { + return error("用户名、密码或验证码不能为空!"); + } + // 前后端同域:使用session存储验证码。如果不同域:使用redis + HttpSession session = request.getSession(); + // 如果验证码session不为空,表示以获取验证码 + + // 使用用户名和密码登录 + SysUser user = userService.login(username, SecureUtil.md5(this.decrypt(password))); + // 如果用户不为空,则登录成功 + if (null != user) { + // 账号状态正常 + if (SystemCode.STATUS_N.getCode() != user.getStatus()) { + // 保持登录与否 + StpUtil.login(user.getId(), "1".equals(remember)); + SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); + return success("登录成功!", tokenInfo); + } + // 账号已被封禁 + else + return error("该账号已被封禁,请联系系统管理员"); + } + // 登录失败 + else { + return error("登录失败:用户名或密码错误"); + } + + } + + /** + * 接口功能:退出登录 + * + * @return JSON:退出登录结果 + */ + @PostMapping(value = "/logout") + @ResponseBody + public BaseResult logout() { + if (StpUtil.isLogin()) { + StpUtil.logout(); + return success("已退出登录!"); + } + return error("请求失败,未登录任何账户"); + } + + /** + * 接口功能:获取用户列表 + * + * @param page 当前页面 + * @param limit 每页请求数 + * @param username 检索用户名 + * @param account 检索电话或邮箱 + * @return JSON:用户列表 | 错误信息 + */ + @GetMapping(value = "/list") + @ResponseBody + public BaseResult getUserList(Integer page, Integer limit, String username, String account) { + Page userPage = userService.getPage(page, limit, username, account); + if (null != userPage) { + return success("查询成功", userPage.getRecords(), (int) userPage.getTotal()); + } else { + return error("查询失败,用户不存在"); + } + } + + /** + * 接口功能:添加用户 + * 基本逻辑:接收前端的用户信息-->校验与初始化新用户信息-->添加至[用户表]-->获取新添加用户的ID-->用户ID与角色ID添加至[用户角色关联表]. + * + * @param user 用户信息 + * @param roleIds 用户分配的角色信息 + * @return JSON:成败结果 + * @apiNote 启用注解[@AnnotationSaveReLog]保存请求日志 + */ + @PostMapping(value = "/add") + @ResponseBody + @AnnotationSaveReLog + public BaseResult add(SysUser user, Integer[] roleIds) { + // 新建用户:其邮箱或手机号、密码不能为空,因为这是登录凭证. + if (null != user && null != user.getPassword() && (null != user.getLoginName() || null != user.getPhone())) { + // 解密 + user.setPassword(SecureUtil.md5(this.decrypt(user.getPassword()))); + // 添加 + if (userService.save(user, roleIds) > 0) { + return success("新用户添加成功!"); + } else { + return error("新用户添加失败,请重试!"); + } + } + return error("用户信息(账号或手机号、密码)不能为空,请重试!"); + } + + /** + * 接口功能:更新用户基本信息(不含角色信息) + * + * @param user 用户信息 + * @return JSON:成败结果 + * @apiNote 启用注解[@AnnotationSaveReLog]保存请求日志 + */ + @PostMapping(value = "/update") + @ResponseBody + @AnnotationSaveReLog + public BaseResult update(SysUser user) { + // 编辑用户基本信息:用户名、头像、性别、邮箱和手机号。 + if (null != user && null != user.getId()) { + // 其他信息(状态、密码)不能通过此接口修改,故其应为null. + if (null == user.getStatus() && null == user.getPassword()) { + if (userService.save(user, null) > 0) { + return success("用户信息编辑成功!"); + } else { + return error("用户信息编辑失败,请重试!"); + } + } else { + return error("接口请求信息错误!"); + } + } else { + return error("用户信息不能为空,请重试!"); + } + } + + /** + * 接口功能:删除用户 + * 基本逻辑:删除该用户的角色信息[用户-角色关联表]-->删除用户 + * + * @param userIds 用户ID列表 + * @return JSON:成败 + * @apiNote 启用注解[@AnnotationSaveReLog]保存请求日志 + */ + @PostMapping(value = "/delete") + @ResponseBody + @AnnotationSaveReLog + public BaseResult delete(Integer[] userIds) { + try { + if (userService.deleteUserById(userIds)[0] > 0) { + return success("用户删除成功"); + } + return error("用户删除失败"); + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:给指定用户分配角色 + * + * @param id 用户ID + * @param roleIds 角色信息列表 + * @return 分配结果 + */ + @PostMapping(value = "/authRole") + @ResponseBody + public BaseResult setRole(String id, Integer[] roleIds) { + try { + if (userService.setRoleForUser(Integer.parseInt(id), roleIds)) { + return success(200, "分配角色成功!"); + } + return success("分配角色失败,请重试!"); + } catch (Exception e) { + return error("发生错误:" + e.getMessage()); + } + + } + + /** + * 接口功能:改变用户的状态 + * + * @param status 新状态:1-正常 0-禁用 + * @param userIds 用户ID列表 + * @return 修改结果 + */ + @PostMapping(value = "/changeStatus/{status}") + @ResponseBody + public BaseResult changeStatus(@PathVariable String status, Integer[] userIds) { + try { + int[] result = userService.changeStatus(Integer.parseInt(status), userIds); + // 没有失败 + if (result[0] != 0 && result[1] == 0) { + return success(200, "用户状态修改成功!"); + } + // 有成功的 + else if (result[0] != 0) { + return success(200, result[0] + "个角色状态更新成功," + result[1] + "个失败!"); + } else { + return success(500, "用户状态修改失败,请重试!"); + } + } catch (Exception e) { + return error(500, "发生错误:" + e.getMessage()); + } + } + + /** + * 接口功能:重置密码 + * + * @param userId 用户ID + * @param newPassword 新密码 + * @param newPassword2 新密码 + * @return 重置结果 + */ + @PostMapping(value = "/resetPassword") + @ResponseBody + @AnnotationSaveReLog + public BaseResult resetPassword(String userId, String newPassword, String newPassword2) { + if (null == userId || null == newPassword || null == newPassword2) { + return error("输入信息有误,请重新输入!"); + } + // 密码先解密 + newPassword = this.decrypt(newPassword); + newPassword2 = this.decrypt(newPassword2); + // 密码相同 + if (newPassword.equals(newPassword2)) { + SysUser user = new SysUser(); + try { + user.setId(Integer.parseInt(userId)); + // 密码MD5加密 + user.setPassword(SecureUtil.md5(newPassword)); + if (userService.save(user, null) > 0) { + return success("密码重置成功!"); + } else { + error("密码重置失败,请重试!"); + } + } catch (Exception e) { + return error(e.getMessage()); + } + } + return error("密码重置失败,新密码不一致!"); + } + + /** + * 接口功能:获取指定角色所分配的用户列表(拥有/不拥有此角色) + * + * @param roleId 角色ID + * @param have 是否用于此角色:0-不拥有 | 1-拥有 + * @return 用户列表 + */ + @GetMapping("/listForRole/{have}/{roleId}") + @ResponseBody + public BaseResult getUserListForRole(@PathVariable("have") String have, @PathVariable("roleId") String roleId) { + try { + // 拥有 此角色 + List userList; + if (have.equals("1")) { + userList = userService.getUserListByRoleId(Integer.parseInt(roleId)); + } + // 不拥有 此角色 + else { + userList = userService.getUserListByRoleIdNotIn(Integer.parseInt(roleId)); + } + return success(200, "获取成功", userList); + } catch (Exception e) { + return error(e.getMessage()); + } + } + + /** + * 访问页面:用户个人信息管理 - 修改用户信息 + * + * @return 跳转至编辑用户页面 + */ + @RequestMapping("center/setting") + public String goSetting(ModelMap map) { + SysUser user = userService.getById(StpUtil.getLoginIdAsInt()); + if (user != null) { + map.put("user", user); + return "system/userCenter/setting"; + } + map.put("code", 404); + map.put("msg", "访问错误!"); + return "error/error"; + } + + /** + * 访问页面:用户管理 - 编辑用户信息页面 + * + * @return 跳转至编辑用户页面 + */ + @RequestMapping("center/password") + public String goChangePassword() { + return "system/userCenter/password"; + } + + /** + * 接口功能:个人中心保存用户信息接口 + * + * @return 结果 + */ + @PostMapping(value = "/center/saveSetting") + @ResponseBody + public BaseResult saveSetting(SysUser user) { + user.setId(StpUtil.getLoginIdAsInt()); +// if (userService.save(user, null) > 0) { +// return success(200, "修改成功"); +// } + return error("修改失败,此接口暂不开放!"); + } + + /** + * 接口功能:个人中心修改用户密码接口 + * + * @param oldPassword 旧密码 + * @param newPassword1 新密码 + * @param newPassword2 新密码 + * @return 修改结果 + */ + @PostMapping(value = "/center/changePassword") + @ResponseBody + public BaseResult changePassword(String oldPassword, String newPassword1, String newPassword2) { + if (!newPassword1.equals(newPassword2)) { + return error("新密码不一致!"); + } + return error("修改失败,此接口暂不开放!"); + } + + /** + * 私有方法:解密密码 + * + * @param encrypt 加密密码 + * @return 解密密码 + */ + private String decrypt(String encrypt) { + // 根据私钥生成新的对象 + RSA rsa = new RSA(exciteConfig.getRsaPrivateKey(), null); + byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey); + return StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8); + } +} diff --git a/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/tool/CaptchaController.java b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/tool/CaptchaController.java new file mode 100644 index 0000000..8203e53 --- /dev/null +++ b/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/tool/CaptchaController.java @@ -0,0 +1,107 @@ +package com.zxdmy.excite.admin.controller.tool; + + +import com.zxdmy.excite.common.base.BaseController; +import com.zxdmy.excite.common.base.BaseResult; + + +import com.zxdmy.excite.common.entity.CaptchaDomain; +import com.zxdmy.excite.common.service.CaptchaService; +import com.zxdmy.excite.common.service.RedisService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Controller; +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.ResponseBody; + +import javax.imageio.ImageIO; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.security.SecureRandom; +import java.util.Random; + +/** + *

+ * 生成验证码接口 + *

+ * + * @author 沈松 + * @since 2021-10-04 0004 21:16 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/tool/captcha") +public class CaptchaController extends BaseController { + + private CaptchaService captchaService; + + private RedisService redisUtils; + + /** + * 获取验证码接口 + * + * @param type 类型,char - 字符(默认) | math - 一位数算式 | math2 - 两位数算式 + * @return 结果 + */ + @GetMapping("/get") + @ResponseBody + public BaseResult getCaptcha(@RequestParam(value = "type", required = false, defaultValue = "char") String type) { + // 生成验证码实体 + CaptchaDomain captchaDomain = captchaService.createGoogleCaptcha(type); + if (null != captchaDomain) { + // 将验证码保存至redis,包含前缀 + redisUtils.set(captchaDomain.getToken(), captchaDomain.getCode(), 300L); + // 无用信息设空 + captchaDomain.setText(null); + captchaDomain.setCode(null); + // 返回前端信息 + return success("获取验证码成功", captchaDomain); + } else { + return error(400, "获取验证码失败,请重试。"); + } + + } + + /** + * 直接输出图片 + * + * @param type 类型,char - 字符(默认) | math - 一位数算式 | math2 - 两位数算式 + */ + @GetMapping("/get/image") + public void getCaptchaImage(@RequestParam(value = "type", required = false, defaultValue = "math") String type) { + ServletOutputStream out = null; + Random random = new SecureRandom(); +// int rand = random.nextInt(2); + CaptchaDomain captchaDomain; +// if (rand == 0) { + // 生成验证码实体 + captchaDomain = captchaService.createGoogleCaptcha(type); +// } else { +// captchaDomain = captchaService.createHutoolCaptcha(160, 60); +// } + // 将验证码保存至session + HttpSession session = request.getSession(); + session.setAttribute("captcha",captchaDomain.getCode()); + // 输出图片 + try { + response.setContentType("image/jpeg"); + out = response.getOutputStream(); + ImageIO.write(captchaDomain.getImage(), "jpg", out); + out.flush(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (out != null) { + out.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + + } + } + +} diff --git a/ss-admin/src/main/resources/application.yml b/ss-admin/src/main/resources/application.yml new file mode 100644 index 0000000..582585f --- /dev/null +++ b/ss-admin/src/main/resources/application.yml @@ -0,0 +1,194 @@ +# 项目服务配置 +server: + port: 8077 # 端口号 + servlet: + context-path: / #项目访问路径 + +# 自定义的配置信息 +excite: + name: Lt-Cloud # 项目名 + allow-redis: true # 开启redis缓存 + rsa-public-key: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxo7epYQqWu4Dgr52LZIn+Y9T3wf2t1NCnh+DpbY3CSBdTDbTyoJdMJm0cat3E7sWcCGqZb2U8Kdtg12ycybhiyuNIc9tXqjYZqBk4ocjuk2QshNFBWU9hgLioKCsbGnCvUY4bB/SuuKUGmNl+CRT7kcehU6u+i3ML88V2LQQKuQIDAQAB" + rsa-private-key: "MIICdAIBADANBgkqhkiG9w0BAQEFAASCAl4wggJaAgEAAoGBALGjt6lhCpa7gOCvnYtkif5j1PfB/a3U0KeH4OltjcJIF1MNtPKgl0wmbRxq3cTuxZwIaplvZTwp22DXbJzJuGLK40hz21eqNhmoGTihyO6TZCyE0UFZT2GAuKgoKxsacK9RjhsH9K64pQaY2X4JFPuRx6FTq76LcwvzxXYtBAq5AgMBAAECfxC5ld7K1gp+wJctnedLlKegE/Wf8prsCCputNKFHE/UecjEqfJ+yPAKEv9SlFuIKOdiuZWTbl+xqgJt9UTzCD8t3E7WTi6yejmhIw1WcmFnDvh7G/AFdfYSxKJ29ak+CEc93SlfaURtxYco71qbjkrUnJi9ALIei4k8i+cEe9ECQQDXq/fm+MiMFTwZEjAimEbu2SZ6E70hbva520WOCkyDDnAvYZ76jtR35rDcIrXEPGGIBKf527iYEpiRriji4CBlAkEA0tstVP+j0UdIb8K1DZ7jj9pKVsBH/5HxLGtE5qk5GnqVwyI3C39/Y1kGY2hkt+7HHQ/uCa29AraymOTntahZxQJBAIsmXTAc2+fl23yhi4UGkt2QJY8mJSTpHy8TFnFqm6sDKcaoSZaHiPZDVWDy1CvkeVj1CBvhc9xKQz3bDG41BTECQGLSPCW5BhLgQK+4Zlhy3h4eZXbQ+S1rPcfeolUkfFHPn/7rOzcVUyPBpn/SflnB++m//ITmu03ZSEzmAz6dHy0CQHRgMPKVPzi70ToLwsWcnhZT6fUv/rkyYIRn4K40l13HNM/6Jj0zEaSMw/Ib4wJx/9l3QgiazeUO0usylxfprug=" + +# Spring相关配置 +spring: + # 数据库链接配置 + datasource: + name: druidDataSource + type: com.alibaba.druid.pool.DruidDataSource + # 链接地址,这里需要修改自己的数据库IP和数据库名 + url: jdbc:mysql://rm-gw0feo75m96osiy49ko.mysql.cn-chengdu.rds.aliyuncs.com:3306/lingtao_file_cloud?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC + username: admin_666888 + password: Admin_666888 + driver-class-name: com.mysql.cj.jdbc.Driver + druid: + # 链接地址,这里需要修改自己的数据库IP和数据库名 + # url: jdbc:mysql://127.0.0.1:3306/db_excite_cms?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC + # username: chen # 数据库用户名 + # password: 123456 # 数据库密码 + initial-size: 1 + min-idle: 1 + max-active: 20 + test-on-borrow: true + # 连接驱动类名 + # MySQL 8.x: com.mysql.cj.jdbc.Driver + # MySQL 5.x: com.mysql.jdbc.Driver + # driver-class-name: com.mysql.cj.jdbc.Driver + # 以下是开启监控相关配置 + webStatFilter: + enabled: true + statViewServlet: + enabled: true + # 设置白名单,不填则允许所有访问 + allow: + url-pattern: /druid/* + # 控制台管理用户名和密码 + 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 + + redis: + # Redis服务器地址 + host: localhost + # password: + # Redis服务器连接端口 + port: 6379 + # 连接超时时间(记得添加单位,Duration) + timeout: 100000ms + # Redis默认情况下有16个分片,这里配置具体使用的分片 + database: 0 + # 自定义属性:开启自定义前缀 + allow-prefix: true + # 自定义属性:key的前缀 + prefix: "com.zxdmy.excite:" + lettuce: + pool: + # 连接池最大连接数(使用负值表示没有限制) 默认 8 + max-active: 100 + # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1 + max-wait: -1ms + # 连接池中的最大空闲连接 默认 8 + max-idle: 8 + # 连接池中的最小空闲连接 默认 0 + min-idle: 0 + thymeleaf: + cache: false #开发时关闭缓存,不然没法实时看到页面 + mode: LEGACYHTML5 #用非严格的HTML(标签不必严格遵守W3C标准) + encoding: UTF-8 # 编码格式 + servlet: + content-type: text/html #内容类型为HTML + prefix: classpath:/templates/ + suffix: .html + + devtools: + restart: + enabled: true + livereload: + enabled: true + + +# Mybatis Plus 相关配置 +mybatis-plus: + # 配置Mapper映射文件 + mapper-locations: classpath*:/mapper/**/**Mapper.xml + # 实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: com.zxdmy.excite.system.entity;com.zxdmy.excite.common.entity + configuration: + # 自动驼峰命名 + map-underscore-to-camel-case: true + auto-mapping-behavior: full + cache-enabled: false + # 打印SQL + log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl + global-config: + db-config: + # 主键类型 0:"数据库ID自增", 1:"用户输入ID", 2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID"; + id-type: auto + # 驼峰下划线转换 + table-underline: true + # 逻辑删除 + logic-delete-value: 1 + logic-not-delete-value: 0 + +# OpenApi 接口文档信息配置 +springdoc: + api-docs: + # 开启或关闭swagger,关闭后,无法访问和查看接口文档 + enabled: true + swagger-ui: + # 打开swagger的地址。当前:http://localhost:8181/swagger + path: /swagger + csrf: + enabled: true # 开启跨域访问 + # 包扫描路径,多个package用英文逗号分隔。如果配置了分组,可以不用设置此项。 + # packages-to-scan: com.zxdmy.excite.system.controller,com.zxdmy.excite.system.entity + # 分组配置, + group-configs: + # 分组名 + - group: system + # 匹配方式1:按路径匹配 + pathsToMatch: /system/** +# # 分组名 +# - group: system +# # 匹配方式2:按包路径匹配;多个package用英文逗号分隔 +# packagesToScan: com.zxdmy.excite.system + +# Sa-Token配置(权限配置使用) +sa-token: + # token名称 (同时也是cookie名称) + token-name: "com.zxdmy.excite" + # token有效期,单位s 默认30天(2592000), -1代表永不过期 + timeout: 259200 + # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒,-1表示永不过期 + activity-timeout: 7200 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # token风格 + token-style: uuid + # 是否输出操作日志 + is-log: true + + + +aliyun: + oss: + #你自己阿里云账户的endpoint + endpoint: oss-cn-hangzhou.aliyuncs.com + #你自己阿里云账户的accessKeyId + accessKeyId: LTAI5tE7wuNkeT9jZ42bQnyr + #你自己阿里云账户的accessKeySecret + accessKeySecret: NnutvWhKl4HbQFSad3HosYbCkEkbjN + #你自己阿里云账户的bucketName + bucketName: ltcloudfile + #Oss前缀路径 + prefix_dir: yangcai365_design + + region: oss-cn-hangzhou + #外网访问域名 + endpointExternal: http://oss-cn-hangzhou.aliyuncs.com + #内网访问域名 + endpointInternal: http://oss-cn-hangzhou-internal.aliyuncs.com + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/banner.txt b/ss-admin/src/main/resources/banner.txt new file mode 100644 index 0000000..bff73ee --- /dev/null +++ b/ss-admin/src/main/resources/banner.txt @@ -0,0 +1,40 @@ +/*##################################################### +# # +# _oo0oo_ # +# o8888888o # +# 88" . "88 # +# (| -_- |) # +# 0\ = /0 # +# ___/`---'\___ # +# .' \\|???? |# '. # +# / \\|||? :? |||# \ # +# / _||||| -:- |||||- \ # +# |?? | \\\? -? #/ |?? | # +# | \_|? ''\---/''? |_/ | # +# \? .-\__? '-'? ___/-. / # +# ___'. .'? /--.--\? `. .'___ # +# ."" '_/___.' >' "". # +# | | :? `- \`.;`\ _ /`;.`/ - ` : | | # +# \? \ `_.?? \_ __\ /__ _/?? .-` /? / # +# =====`-.____`.___ \_____/___.-`___.-'===== # +# `=---=' # +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # +# # +# 佛祖保佑 永无BVG # +# # +#####################################################*/ + + + ┌─────────────────────────────────────────────┐ + │ 🙏 南无阿弥陀佛 🙏 │ + │ 🐛 永无bug 🎯 │ + │ │ + │ 🌸 Spring Boot 加持中... │ + │ 🪷 代码清净无染 │ + │ 📿 运行稳定如常 │ + └─────────────────────────────────────────────┘ + +应用: ${spring.application.name} +端口: ${server.port} +环境: ${spring.profiles.active:default} +内存: ${java.vm.name} ${java.vm.version} diff --git a/ss-admin/src/main/resources/static/api/clear.json b/ss-admin/src/main/resources/static/api/clear.json new file mode 100644 index 0000000..e0f5ed7 --- /dev/null +++ b/ss-admin/src/main/resources/static/api/clear.json @@ -0,0 +1,4 @@ +{ + "code": 1, + "msg": "服务端清理缓存成功" +} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/api/init.json b/ss-admin/src/main/resources/static/api/init.json new file mode 100644 index 0000000..8c7383c --- /dev/null +++ b/ss-admin/src/main/resources/static/api/init.json @@ -0,0 +1,245 @@ +{ + "homeInfo": { + "title": "首页", + "href": "page/welcome-1.html?t=1" + }, + "logoInfo": { + "title": "LAYUI MINI", + "image": "images/logo.png", + "href": "" + }, + "menuInfo": [ + { + "title": "常规管理", + "icon": "fa fa-address-book", + "href": "", + "target": "_self", + "child": [ + { + "title": "主页模板", + "href": "", + "icon": "fa fa-home", + "target": "_self", + "child": [ + { + "title": "主页一", + "href": "page/welcome-1.html", + "icon": "fa fa-tachometer", + "target": "_self" + }, + { + "title": "主页二", + "href": "page/welcome-2.html", + "icon": "fa fa-tachometer", + "target": "_self" + }, + { + "title": "主页三", + "href": "page/welcome-3.html", + "icon": "fa fa-tachometer", + "target": "_self" + } + ] + }, + { + "title": "菜单管理", + "href": "page/menu.html", + "icon": "fa fa-window-maximize", + "target": "_self" + }, + { + "title": "系统设置", + "href": "page/setting.html", + "icon": "fa fa-gears", + "target": "_self" + }, + { + "title": "表格示例", + "href": "page/table.html", + "icon": "fa fa-file-text", + "target": "_self" + }, + { + "title": "表单示例", + "href": "", + "icon": "fa fa-calendar", + "target": "_self", + "child": [ + { + "title": "普通表单", + "href": "page/form.html", + "icon": "fa fa-list-alt", + "target": "_self" + }, + { + "title": "分步表单", + "href": "page/form-step.html", + "icon": "fa fa-navicon", + "target": "_self" + } + ] + }, + { + "title": "登录模板", + "href": "", + "icon": "fa fa-flag-o", + "target": "_self", + "child": [ + { + "title": "登录-1", + "href": "page/login-1.html", + "icon": "fa fa-stumbleupon-circle", + "target": "_blank" + }, + { + "title": "登录-2", + "href": "page/login-2.html", + "icon": "fa fa-viacoin", + "target": "_blank" + }, + { + "title": "登录-3", + "href": "page/login-3.html", + "icon": "fa fa-tags", + "target": "_blank" + } + ] + }, + { + "title": "异常页面", + "href": "", + "icon": "fa fa-home", + "target": "_self", + "child": [ + { + "title": "404页面", + "href": "page/404.html", + "icon": "fa fa-hourglass-end", + "target": "_self" + } + ] + }, + { + "title": "其它界面", + "href": "", + "icon": "fa fa-snowflake-o", + "target": "", + "child": [ + { + "title": "按钮示例", + "href": "page/button.html", + "icon": "fa fa-snowflake-o", + "target": "_self" + }, + { + "title": "弹出层", + "href": "page/layer.html", + "icon": "fa fa-shield", + "target": "_self" + } + ] + } + ] + }, + { + "title": "组件管理", + "icon": "fa fa-lemon-o", + "href": "", + "target": "_self", + "child": [ + { + "title": "图标列表", + "href": "page/icon.html", + "icon": "fa fa-dot-circle-o", + "target": "_self" + }, + { + "title": "图标选择", + "href": "page/icon-picker.html", + "icon": "fa fa-adn", + "target": "_self" + }, + { + "title": "颜色选择", + "href": "page/color-select.html", + "icon": "fa fa-dashboard", + "target": "_self" + }, + { + "title": "下拉选择", + "href": "page/table-select.html", + "icon": "fa fa-angle-double-down", + "target": "_self" + }, + { + "title": "文件上传", + "href": "page/upload.html", + "icon": "fa fa-arrow-up", + "target": "_self" + }, + { + "title": "富文本编辑器", + "href": "page/editor.html", + "icon": "fa fa-edit", + "target": "_self" + }, + { + "title": "省市县区选择器", + "href": "page/area.html", + "icon": "fa fa-rocket", + "target": "_self" + } + ] + }, + { + "title": "其它管理", + "icon": "fa fa-slideshare", + "href": "", + "target": "_self", + "child": [ + { + "title": "多级菜单", + "href": "", + "icon": "fa fa-meetup", + "target": "", + "child": [ + { + "title": "按钮1", + "href": "page/button.html?v=1", + "icon": "fa fa-calendar", + "target": "_self", + "child": [ + { + "title": "按钮2", + "href": "page/button.html?v=2", + "icon": "fa fa-snowflake-o", + "target": "_self", + "child": [ + { + "title": "按钮3", + "href": "page/button.html?v=3", + "icon": "fa fa-snowflake-o", + "target": "_self" + }, + { + "title": "表单4", + "href": "page/form.html?v=1", + "icon": "fa fa-calendar", + "target": "_self" + } + ] + } + ] + } + ] + }, + { + "title": "失效菜单", + "href": "page/error.html", + "icon": "fa fa-superpowers", + "target": "_self" + } + ] + } + ] +} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/api/menus.json b/ss-admin/src/main/resources/static/api/menus.json new file mode 100644 index 0000000..e14d00e --- /dev/null +++ b/ss-admin/src/main/resources/static/api/menus.json @@ -0,0 +1,254 @@ +{ + "code": 0, + "msg": "", + "count": 19, + "data": [ + { + "authorityId": 1, + "authorityName": "系统管理", + "orderNumber": 1, + "menuUrl": null, + "menuIcon": "layui-icon-set", + "createTime": "2018/06/29 11:05:41", + "authority": null, + "checked": 0, + "updateTime": "2018/07/13 09:13:42", + "isMenu": 0, + "parentId": -1 + }, + { + "authorityId": 2, + "authorityName": "用户管理", + "orderNumber": 2, + "menuUrl": "system/user", + "menuIcon": null, + "createTime": "2018/06/29 11:05:41", + "authority": null, + "checked": 0, + "updateTime": "2018/07/13 09:13:42", + "isMenu": 0, + "parentId": 1 + }, + { + "authorityId": 3, + "authorityName": "查询用户", + "orderNumber": 3, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/07/21 13:54:16", + "authority": "user:view", + "checked": 0, + "updateTime": "2018/07/21 13:54:16", + "isMenu": 1, + "parentId": 2 + }, + { + "authorityId": 4, + "authorityName": "添加用户", + "orderNumber": 4, + "menuUrl": null, + "menuIcon": null, + "createTime": "2018/06/29 11:05:41", + "authority": "user:add", + "checked": 0, + "updateTime": "2018/07/13 09:13:42", + "isMenu": 1, + "parentId": 2 + }, + { + "authorityId": 5, + "authorityName": "修改用户", + "orderNumber": 5, + "menuUrl": null, + "menuIcon": null, + "createTime": "2018/06/29 11:05:41", + "authority": "user:edit", + "checked": 0, + "updateTime": "2018/07/13 09:13:42", + "isMenu": 1, + "parentId": 2 + }, + { + "authorityId": 6, + "authorityName": "删除用户", + "orderNumber": 6, + "menuUrl": null, + "menuIcon": null, + "createTime": "2018/06/29 11:05:41", + "authority": "user:delete", + "checked": 0, + "updateTime": "2018/07/13 09:13:42", + "isMenu": 1, + "parentId": 2 + }, + { + "authorityId": 7, + "authorityName": "角色管理", + "orderNumber": 7, + "menuUrl": "system/role", + "menuIcon": null, + "createTime": "2018/06/29 11:05:41", + "authority": null, + "checked": 0, + "updateTime": "2018/07/13 09:13:42", + "isMenu": 0, + "parentId": 1 + }, + { + "authorityId": 8, + "authorityName": "查询角色", + "orderNumber": 8, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/07/21 13:54:59", + "authority": "role:view", + "checked": 0, + "updateTime": "2018/07/21 13:54:58", + "isMenu": 1, + "parentId": 7 + }, + { + "authorityId": 9, + "authorityName": "添加角色", + "orderNumber": 9, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/06/29 11:05:41", + "authority": "role:add", + "checked": 0, + "updateTime": "2018/07/13 09:13:42", + "isMenu": 1, + "parentId": 7 + }, + { + "authorityId": 10, + "authorityName": "修改角色", + "orderNumber": 10, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/06/29 11:05:41", + "authority": "role:edit", + "checked": 0, + "updateTime": "2018/07/13 09:13:42", + "isMenu": 1, + "parentId": 7 + }, + { + "authorityId": 11, + "authorityName": "删除角色", + "orderNumber": 11, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/06/29 11:05:41", + "authority": "role:delete", + "checked": 0, + "updateTime": "2018/07/13 09:13:42", + "isMenu": 1, + "parentId": 7 + }, + { + "authorityId": 12, + "authorityName": "角色权限管理", + "orderNumber": 12, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/06/29 11:05:41", + "authority": "role:auth", + "checked": 0, + "updateTime": "2018/07/13 15:27:18", + "isMenu": 1, + "parentId": 7 + }, + { + "authorityId": 13, + "authorityName": "权限管理", + "orderNumber": 13, + "menuUrl": "system/authorities", + "menuIcon": null, + "createTime": "2018/06/29 11:05:41", + "authority": null, + "checked": 0, + "updateTime": "2018/07/13 15:45:13", + "isMenu": 0, + "parentId": 1 + }, + { + "authorityId": 14, + "authorityName": "查询权限", + "orderNumber": 14, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/07/21 13:55:57", + "authority": "authorities:view", + "checked": 0, + "updateTime": "2018/07/21 13:55:56", + "isMenu": 1, + "parentId": 13 + }, + { + "authorityId": 15, + "authorityName": "添加权限", + "orderNumber": 15, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/06/29 11:05:41", + "authority": "authorities:add", + "checked": 0, + "updateTime": "2018/06/29 11:05:41", + "isMenu": 1, + "parentId": 13 + }, + { + "authorityId": 16, + "authorityName": "修改权限", + "orderNumber": 16, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/07/13 09:13:42", + "authority": "authorities:edit", + "checked": 0, + "updateTime": "2018/07/13 09:13:42", + "isMenu": 1, + "parentId": 13 + }, + { + "authorityId": 17, + "authorityName": "删除权限", + "orderNumber": 17, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/06/29 11:05:41", + "authority": "authorities:delete", + "checked": 0, + "updateTime": "2018/06/29 11:05:41", + "isMenu": 1, + "parentId": 13 + }, + { + "authorityId": 18, + "authorityName": "登录日志", + "orderNumber": 18, + "menuUrl": "system/loginRecord", + "menuIcon": null, + "createTime": "2018/06/29 11:05:41", + "authority": null, + "checked": 0, + "updateTime": "2018/06/29 11:05:41", + "isMenu": 0, + "parentId": 1 + }, + { + "authorityId": 19, + "authorityName": "查询登录日志", + "orderNumber": 19, + "menuUrl": "", + "menuIcon": "", + "createTime": "2018/07/21 13:56:43", + "authority": "loginRecord:view", + "checked": 0, + "updateTime": "2018/07/21 13:56:43", + "isMenu": 1, + "parentId": 18 + } + ] +} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/api/table.json b/ss-admin/src/main/resources/static/api/table.json new file mode 100644 index 0000000..7bda61b --- /dev/null +++ b/ss-admin/src/main/resources/static/api/table.json @@ -0,0 +1,127 @@ +{ + "code": 0, + "msg": "", + "count": 1000, + "data": [ + { + "id": 10000, + "username": "user-0", + "sex": "女", + "city": "城市-0", + "sign": "签名-0", + "experience": 255, + "logins": 24, + "wealth": 82830700, + "classify": "作家", + "score": 57 + }, + { + "id": 10001, + "username": "user-1", + "sex": "男", + "city": "城市-1", + "sign": "签名-1", + "experience": 884, + "logins": 58, + "wealth": 64928690, + "classify": "词人", + "score": 27 + }, + { + "id": 10002, + "username": "user-2", + "sex": "女", + "city": "城市-2", + "sign": "签名-2", + "experience": 650, + "logins": 77, + "wealth": 6298078, + "classify": "酱油", + "score": 31 + }, + { + "id": 10003, + "username": "user-3", + "sex": "女", + "city": "城市-3", + "sign": "签名-3", + "experience": 362, + "logins": 157, + "wealth": 37117017, + "classify": "诗人", + "score": 68 + }, + { + "id": 10004, + "username": "user-4", + "sex": "男", + "city": "城市-4", + "sign": "签名-4", + "experience": 807, + "logins": 51, + "wealth": 76263262, + "classify": "作家", + "score": 6 + }, + { + "id": 10005, + "username": "user-5", + "sex": "女", + "city": "城市-5", + "sign": "签名-5", + "experience": 173, + "logins": 68, + "wealth": 60344147, + "classify": "作家", + "score": 87 + }, + { + "id": 10006, + "username": "user-6", + "sex": "女", + "city": "城市-6", + "sign": "签名-6", + "experience": 982, + "logins": 37, + "wealth": 57768166, + "classify": "作家", + "score": 34 + }, + { + "id": 10007, + "username": "user-7", + "sex": "男", + "city": "城市-7", + "sign": "签名-7", + "experience": 727, + "logins": 150, + "wealth": 82030578, + "classify": "作家", + "score": 28 + }, + { + "id": 10008, + "username": "user-8", + "sex": "男", + "city": "城市-8", + "sign": "签名-8", + "experience": 951, + "logins": 133, + "wealth": 16503371, + "classify": "词人", + "score": 14 + }, + { + "id": 10009, + "username": "user-9", + "sex": "女", + "city": "城市-9", + "sign": "签名-9", + "experience": 484, + "logins": 25, + "wealth": 86801934, + "classify": "词人", + "score": 75 + } + ] +} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/api/tableSelect.json b/ss-admin/src/main/resources/static/api/tableSelect.json new file mode 100644 index 0000000..37fb0ed --- /dev/null +++ b/ss-admin/src/main/resources/static/api/tableSelect.json @@ -0,0 +1,23 @@ +{ + "code": 0, + "msg": "", + "count": 16, + "data": [ + { "id":"001", "username":"张玉林", "sex":"女" }, + { "id":"002", "username":"刘晓军", "sex":"男" }, + { "id":"003", "username":"张恒", "sex":"男" }, + { "id":"004", "username":"朱一", "sex":"男" }, + { "id":"005", "username":"刘佳能", "sex":"女" }, + { "id":"006", "username":"晓梅", "sex":"女" }, + { "id":"007", "username":"马冬梅", "sex":"女" }, + { "id":"008", "username":"刘晓庆", "sex":"女" }, + { "id":"009", "username":"刘晓庆", "sex":"女" }, + { "id":"010", "username":"刘晓庆", "sex":"女" }, + { "id":"011", "username":"刘晓庆", "sex":"女" }, + { "id":"012", "username":"刘晓庆", "sex":"女" }, + { "id":"013", "username":"刘晓庆", "sex":"女" }, + { "id":"014", "username":"刘晓庆", "sex":"女" }, + { "id":"015", "username":"刘晓庆", "sex":"女" }, + { "id":"016", "username":"刘晓庆", "sex":"女" } + ] +} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/api/upload.json b/ss-admin/src/main/resources/static/api/upload.json new file mode 100644 index 0000000..691902d --- /dev/null +++ b/ss-admin/src/main/resources/static/api/upload.json @@ -0,0 +1,10 @@ +{ + "code": 1, + "msg": "上传成功", + "data": { + "url": [ + "../images/logo.png", + "../images/captcha.jpg" + ] + } +} diff --git a/ss-admin/src/main/resources/static/css/layuimini.css b/ss-admin/src/main/resources/static/css/layuimini.css new file mode 100644 index 0000000..6a96476 --- /dev/null +++ b/ss-admin/src/main/resources/static/css/layuimini.css @@ -0,0 +1,927 @@ +/** +配色方案(如有需要,请自行配置) + */ +/**头部-配色*/ +.layui-layout-admin .layui-header { + background-color: #1aa094 !important; +} + +.layui-header > ul > .layui-nav-item.layui-this, .layuimini-tool i:hover { + background-color: #197971 !important; +} + +.layui-header .layuimini-header-content > ul > .layui-nav-item.layui-this, .layuimini-tool i:hover { + background-color: #197971 !important; +} + +/**logo-配色*/ +.layui-layout-admin .layuimini-logo { + background-color: #ffffff !important; +} + +/**左侧-配色*/ +.layui-side.layui-bg-black, .layui-side.layui-bg-black > .layuimini-menu-left > ul { + background-color: #ffffff !important; +} + +.layuimini-menu-left .layui-nav .layui-nav-child a:hover:not(.layui-this) { + background-color: #3b3f4b; +} + +/**左侧菜单选中-配色*/ +.layui-layout-admin .layui-nav-tree .layui-this, .layui-layout-admin .layui-nav-tree .layui-this > a, .layui-layout-admin .layui-nav-tree .layui-nav-child dd.layui-this, .layui-layout-admin .layui-nav-tree .layui-nav-child dd.layui-this a { + background-color: #1aa094 !important; +} + + +/**头部样式 */ +.layui-layout-admin .header { + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; +} + +.layuimini-header-menu, .layui-header { + height: 60px !important; +} + +.layuimini-header-menu > .layui-nav-item { + color: #1b1d21; + height: 60px !important; + line-height: 60px !important; +} + +.layui-header > .layui-layout-right > .layui-nav-item { + height: 60px !important; + line-height: 60px !important; +} + +.layui-layout-left { + left: 295px !important; +} + +.layui-nav.layui-layout-left.layuimini-header-menu.layuimini-pc-show { + font-weight: bold; + transition: all .2s; +} + + +/**logo演示(通用) */ +.layui-layout-admin .layuimini-logo { + font-weight: bold; + color: #ffffff !important; + height: 60px !important; + line-height: 60px !important; + overflow: hidden; + line-height: 64px; + transition: all .2s !important; +} + +.layui-layout-admin .layuimini-logo img { + display: inline-block; + height: 40px; + vertical-align: middle; +} + +.layui-layout-admin .layuimini-logo h1 { + display: inline-block; + margin: 0 0 0 12px; + color: #ffffff; + font-weight: 600; + font-size: 20px; + font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; + vertical-align: middle; +} + +/**缩放工具(通用) */ +.layuimini-tool { + position: absolute !important; + top: 0; + left: 235px; + width: 60px; + height: 100%; + line-height: 60px; + text-align: center; + color: #ffffff !important; + transition: all .2s; +} + +/**缩放工具(缩放) */ +.layuimini-tool i { + display: block; + color: #bbe3df; + width: 32px; + height: 32px; + line-height: 32px; + border-radius: 3px; + text-align: center; + margin-top: 15px; + cursor: pointer; +} + +/**tab选项卡 */ +.layuimini-tab { + margin: 0px; + overflow: hidden; + height: 100% !important; +} + +.layuimini-tab .layui-tab-content { + height: calc(100% - 37px) !important; +} + +.layuimini-tab .layui-tab-content .layui-tab-item { + height: 100%; +} + +.layuimini-tab .layui-tab-content { + padding: 0px; +} + +.layuimini-tab .layui-tab-title { + border: none; + border: 1px solid whitesmoke; + background-color: white; +} + +.layuimini-tab .layui-tab-title li { + border-right: 1px solid whitesmoke; + color: dimgray; +} + +.layuimini-tab .layui-tab-title .layui-tab-bar { + display: none; +} + +.layuimini-tab .layui-tab-title .layui-this:after { + display: none; +} + +.layuimini-tab .layui-tab-title .layuimini-tab-active { + display: inline-block; + background-color: lightgray; + width: 9px; + height: 9px; + border-radius: 30px; + margin-right: 5px; +} + +.layuimini-tab .layui-tab-title .layui-this .layuimini-tab-active { + background-color: #1aa094; +} + +.layuimini-tab > .layui-tab-title, .layuimini-tab > .close-box { + height: 35px !important; +} + +.layuimini-tab > .layui-tab-title li, .layuimini-tab > .close-box li { + line-height: 35px !important; +} + +.layuimini-tab .layui-tab-title span { + color: #616161; +} + +.layuimini-tab .layui-tab-title .layui-this span { + color: #070707; +} + +.layuimini-tab .layui-tab-title .layui-tab-close { + font-size: 12px !important; + width: 14px !important; + height: 14px !important; + line-height: 16px !important; +} + +.layuimini-tab .layui-tab-title .layui-tab-close:hover { + border-radius: 4em; + background: #ff5722; +} + +.layuimini-tab .layui-tab-title .disable-close + .layui-tab-close { + display: none; +} + +.layuimini-tab .layui-tab-title .able-close + .layui-tab-close { + display: inline-block; +} + +.layuimini-tab .layui-tab-control > li { + position: absolute; + top: 0px; + height: 35px; + line-height: 35px; + width: 35px; + text-align: center; + background-color: white; + border-top: whitesmoke 1px solid; + border-bottom: whitesmoke 1px solid; +} + +.layuimini-tab .layuimini-tab-roll-left { + left: 0px; + border-right: whitesmoke 1px solid; + border-left: whitesmoke 1px solid; +} + +.layuimini-tab .layuimini-tab-roll-right { + right: 35px; + border-left: 1px solid whitesmoke; +} + +.layuimini-tab .layui-tab-tool { + right: 0px; + border-left: 1px solid whitesmoke; +} + +.layuimini-tab .layui-tab-control .layui-tab-tool, +.layuimini-tab .layui-tab-control .layuimini-tab-roll-left, +.layuimini-tab .layui-tab-control .layuimini-tab-roll-right { + display: none; +} + +.layuimini-tab.layui-tab-roll .layui-tab-control .layuimini-tab-roll-left, +.layuimini-tab.layui-tab-roll .layui-tab-control .layuimini-tab-roll-right { + display: block; +} + +.layuimini-tab.layui-tab-roll .layui-tab-control .layuimini-tab-roll-right { + right: 0px; + border-right: 1px solid whitesmoke; +} + +.layuimini-tab.layui-tab-roll .layui-tab-title { + padding-left: 35px; + padding-right: 35px; +} + + +.layuimini-tab.layui-tab-tool .layui-tab-control .layui-tab-tool { + display: block; +} + +.layuimini-tab.layui-tab-tool .layui-tab-title { + padding-left: 0px; + padding-right: 35px; +} + + +.layuimini-tab.layui-tab-rollTool .layui-tab-title { + padding-left: 35px; + padding-right: 80px; +} + +.layuimini-tab.layui-tab-rollTool .layui-tab-control .layuimini-tab-roll-left, +.layuimini-tab.layui-tab-rollTool .layui-tab-control .layuimini-tab-roll-right, +.layuimini-tab.layui-tab-rollTool .layui-tab-control .layui-tab-tool { + display: block; +} + +.layuimini-tab .layui-tab-tool .layui-nav { + position: absolute; + height: 43px !important; + top: 0; + width: 100%; + height: 100%; + padding: 0; + background: 0 0; +} + +.layuimini-tab .layui-tab-tool .layui-nav-item { + height: 35px; +} + +.layuimini-tab .layui-tab-tool .layui-nav-bar { + display: none; +} + +.layuimini-tab .layui-tab-tool .layui-nav-child { + left: auto; + top: 45px; + right: 3px; + width: 120px; + border: 1px solid whitesmoke; +} + +.layuimini-tab .layui-tab-tool .layui-this a { + background-color: #009688; +} + +.layuimini-tab-loading { + position: absolute; + display: none; + width: 100%; + height: calc(100% - 37px); + top: 37px; + z-index: 19; + background-color: #fff +} + +.layuimini-tab-loading.close { + animation: close 1s; + -webkit-animation: close 1s; + animation-fill-mode: forwards; +} + +/**左侧菜单栏 (通用) */ +.layui-side.layui-bg-black { + transition: all .2s; +} + +.layui-side.layui-bg-black > .layuimini-menu-left > ul { + transition: all .2s; +} + +.layui-side.layui-bg-black > .layuimini-menu-left > ul > .layui-nav-item:first-child { + border-top: 1px solid #4b5461; +} + +.layuimini-menu-left .layui-nav .layui-nav-item a { + height: 40px; + line-height: 40px; + padding-right: 30px; +} + +.layuimini-menu-left .layui-nav .layui-nav-item > a { + padding-top: 5px; + padding-bottom: 5px; +} + +.layuimini-menu-left .layui-nav .layui-nav-child .layui-nav-child { + background: 0 0 !important +} + +.layuimini-menu-left .layui-nav .layui-nav-more { + right: 15px; +} + +.layuimini-menu-left .layui-nav .layui-nav-item a:hover { + background-color: transparent !important; +} + +.layuimini-menu-left .layui-nav { + background-color: transparent !important; +} + + +/**左侧菜单栏 (正常) */ +.layui-layout-body .layui-nav-itemed .layui-nav-child a, .layui-layout-body .layuimini-menu-left .layui-nav .layui-nav-child a { + padding-left: 35px; +} + +.layui-layout-body .layuimini-menu-left .layui-nav .layui-nav-child .layui-nav-child a { + padding-left: 45px; +} + +.layui-layout-body .layuimini-menu-left .layui-nav .layui-nav-child .layui-nav-child .layui-nav-child a { + padding-left: 55px; +} + +.layui-layout-body .layuimini-menu-left .layui-nav .layui-nav-child .layui-nav-child .layui-nav-child .layui-nav-child a { + padding-left: 65px; +} + +.layui-layout-body .layuimini-menu-left .layui-nav .layui-nav-itemed > .layui-nav-child { + padding: 5px 0; +} + +/**内容主体(通用) */ +.layui-layout-admin .layui-body { + overflow: hidden; + bottom: 0px !important; + top: 60px !important; + transition: all .2s; +} + +/**选择配色方案 */ +.layuimini-color .color-title { + padding: 10px 0 10px 20px; + border-bottom: 1px solid #d9dada; + margin-bottom: 8px; +} + +.layuimini-color .color-content { + padding: 10px 5px 0 5px; +} + +.layuimini-color .color-content ul { + list-style: none; + text-align: center; +} + +.layuimini-color .color-content ul li { + position: relative; + display: inline-block; + vertical-align: top; + width: 80px; + height: 50px; + margin: 0 15px 15px 0; + padding: 2px 2px 4px 2px; + background-color: #f2f2f2; + cursor: pointer; + font-size: 12px; + color: #666; +} + +.layuimini-color .color-content li.layui-this:after, .layuimini-color .color-content li:hover:after { + width: 100%; + height: 100%; + padding: 4px; + top: -5px; + left: -5px; + border-color: #d8d8d8; + opacity: 1; +} + +.layuimini-color .color-content li:after { + content: ''; + position: absolute; + z-index: 20; + top: 50%; + left: 50%; + width: 1px; + height: 0; + border: 1px solid #f2f2f2; + transition: all .3s; + -webkit-transition: all .3s; + opacity: 0; +} + + +/**其它 */ +.layui-tab-item { + width: 100% !important; + height: 100% !important; +} + +.layui-nav-item.layui-this { + background-color: #1b1d21; +} + +.layui-width-height { + width: 100%; + height: 95%; +} + +.layui-tab { + margin: 0 0 0 0; + z-index: 99999; +} + +.text-center { + height: 30px !important; + line-height: 30px !important; + text-align: center !important; +} + +.layui-nav { + padding: 0 !important; +} + +.layui-nav .layui-this:after, .layui-nav-bar, .layui-nav-tree .layui-nav-itemed:after { + width: 0 !important; + height: 0 !important; +} + +.layui-layout-admin .layui-side { + top: 60px !important; +} + +.layui-tab-card { + box-shadow: 0px 0px 0px #888888; + border-bottom: 0; +} + + +/**自定义滚动条样式 */ +::-webkit-scrollbar { + display: none +} + + +/*移动端遮罩层*/ +.layuimini-make { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 1000; + background: rgba(0, 0, 0, .5); + display: none; +} + +.layuimini-mini .layui-header { + z-index: 1001; +} + +/**初始化加载层*/ +.layuimini-loader { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #ffffff; + z-index: 999999; +} + +.layuimini-loader .layuimini-loader-inner { + display: block; + position: relative; + left: 50%; + top: 50%; + width: 150px; + height: 150px; + margin: -75px 0 0 -75px; + border-radius: 50%; + border: 3px solid transparent; + border-top-color: #1E9FFF; + animation: spin 2s linear infinite; +} + +.layuimini-loader .layuimini-loader-inner:before { + content: ""; + position: absolute; + top: 5px; + left: 5px; + right: 5px; + bottom: 5px; + border-radius: 50%; + border: 3px solid transparent; + border-top-color: #1E9FFF; + animation: spin 3s linear infinite; +} + +.layuimini-loader .layuimini-loader-inner:after { + content: ""; + position: absolute; + top: 15px; + left: 15px; + right: 15px; + bottom: 15px; + border-radius: 50%; + border: 3px solid transparent; + border-top-color: #1E9FFF; + animation: spin 1.5s linear infinite; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + to { + transform: rotate(1turn); + } +} + +/*系统设置*/ + +.layuimini-color .layui-word-aux { + position: absolute; + left: 60px; + top: 12px; + font-size: 12px; +} + +.layuimini-color .layui-input-block { + margin-left: 15px; + min-height: 36px; +} + +.layuimini-color .more-menu-list { + width: 100%; + margin-top: 30px; +} + + +.layuimini-color .more-menu-item:first-child { + border-top: 1px solid #e8e8e8; +} + +.layuimini-color .more-menu-item .layui-icon { + font-size: 18px; + padding-right: 10px; +} + +.layuimini-color .more-menu-item { + color: #595959; + height: 50px; + line-height: 50px; + font-size: 16px; + padding: 0 25px; + border-bottom: 1px solid #e8e8e8; + font-style: normal; + display: block; +} + +.layuimini-color .more-menu-item:hover { + background-color: whitesmoke; +} + +.layuimini-color .more-menu-item:after { + color: #8c8c8c; + right: 16px; + content: "\e602"; + position: absolute; + font-family: layui-icon !important; +} + +/** +鼠标右键 + */ +.layuimini-tab-mousedown { + display: none; + width: 80px; + position: absolute; + top: 0px !important; + left: 0px !important; +} + +.layuimini-tab-mousedown dd a { + padding: 0 5px; + color: #484545; +} + +.layuimini-tab-make{ + position: absolute; + top: 36px; + bottom: 0px; + width: 100%; + background: rgb(255, 255, 255,0); + padding: 0px; + overflow: hidden; +} + +/** +菜单缩放 + */ +.popup-tips .layui-layer-TipsG{ + display: none; +} +.popup-tips.layui-layer-tips .layui-layer-content{ + padding: 0; +} +.popup-tips .layui-nav-tree{ + width: 150px; + border-radius: 10px; +} + +/**左侧菜单字体间距*/ +.layuimini-menu-left .layui-nav-item a span { + letter-spacing: 1px; +} + +/**头部菜单字体间距*/ +.layui-layout-admin .layui-header .layuimini-header-menu.layuimini-pc-show,.layui-layout-admin .layui-header .layuimini-header-menu.layuimini-mobile-show { + letter-spacing: 1px; +} + + +/**左侧菜单更多下拉样式*/ +.layuimini-menu-left .layui-nav-more,.layuimini-menu-left-zoom .layui-nav-more { + font-family: layui-icon !important; + font-size: 12px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + overflow: hidden; + width: auto; + height: auto; + line-height: normal; + border: none; + display: inline-block; + margin-top: -6px !important; +} + +.layuimini-menu-left .layui-nav-child .layui-nav-more { + margin-top: -6px !important; +} + +.layuimini-menu-left .layui-nav .layui-nav-mored,.layuimini-menu-left .layui-nav-itemed>a .layui-nav-more{ + margin-top: -9px!important; +} + +.layuimini-menu-left-zoom.layui-nav .layui-nav-mored,.layuimini-menu-left-zoom.layui-nav-itemed>a .layui-nav-more{ + margin-top: -9px!important; +} + +.layuimini-menu-left .layui-nav-more:before,.layuimini-menu-left-zoom .layui-nav-more:before { + content: "\e61a"; +} +.layuimini-menu-left .layui-nav-itemed > a > .layui-nav-more,.layuimini-menu-left-zoom .layui-nav-itemed > a > .layui-nav-more { + transform: rotate(180deg); + -ms-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -webkit-transform: rotate(180deg); + -o-transform: rotate(180deg); + width: 12px; + text-align: center; + border-style:none; +} + +.layuimini-menu-left .layui-nav-itemed > a > .layui-nav-more:before,.layuimini-menu-left-zoom .layui-nav-itemed > a > .layui-nav-more:before { + content: '\e61a'; + background-color: transparent; + display: inline-block; + vertical-align: middle; +} + +/**修复左侧菜单字体不对齐的问题*/ +.layuimini-menu-left .layui-nav-item a .fa,.layuimini-menu-left .layui-nav-item a .layui-icon{ + width: 20px; +} + + +/** + PC版样式 + */ +@media screen and (min-width: 1025px) { + /**头部样式(缩放) */ + .layuimini-mini .layui-layout-left.layuimini-header-menu.layuimini-pc-show { + left: 155px !important; + } + + /**logo演示(缩放) */ + .layuimini-mini .layui-layout-admin .layuimini-logo { + width: 60px !important; + } + + .layuimini-mini .layui-layout-admin .layuimini-logo h1 { + display: none; + } + + /**左侧菜单栏(缩放) */ + .layuimini-mini .layuimini-menu-left { + width: 80px !important; + } + + .layuimini-mini .layui-side.layui-bg-black, .layuimini-mini .layuimini-menu-left > ul, .layuimini-mini .layuimini-menu-left > ul li i { + width: 60px !important; + } + + .layuimini-mini .layuimini-menu-left > ul li span:first-child { + display: none; + } + + .layuimini-mini .layuimini-menu-left > ul li span:last-child { + float: right; + right: 7px; + } + + .layuimini-mini .layuimini-menu-left .layui-nav .layui-nav-item a { + height: 40px; + line-height: 40px; + padding-right: 0px !important; + } + + /**内容主体(缩放) */ + .layuimini-mini .layui-layout-admin .layui-body { + left: 60px !important; + } + + .layuimini-mini .layuimini-tool { + left: 95px !important; + } + + .layuimini-pc-show{ + display: block; + } + .layuimini-mobile-show{ + display: none; + } + + /**菜单缩放*/ + .layuimini-mini .layuimini-menu-left .layui-nav-more,.layuimini-mini .layuimini-menu-left .layui-nav-child{ + display: none;!important; + } +} + +/** + 手机自适应样式 +*/ +@media screen and (max-width: 1024px) { + + /** + 修复低版本IOS不能滑动问题, 但还是有问题, 低版本IOS部分情况下子页面无法自适应 + */ + .layuimini-tab .layui-tab-content .layui-tab-item { + -webkit-overflow-scrolling: touch; + overflow: scroll; + width: 100%; + height: 100%; + } + + .layuimini-tab .layui-tab-content .layui-tab-item iframe { + height: 100%; + width: 100%; + } + + .layuimini-pc-show{ + display: none; + } + .layuimini-mobile-show{ + display: block; + } + .layuimini-header-content { + left: 0; + } + + .layui-layout-admin .layui-body .layui-tab-item.layui-show { + border-top: 1px solid #e2e2e2; + } + + .layuimini-all .layui-layout-left.layuimini-header-menu { + left: 15px !important + } + + .layuimini-mini .layui-layout-left.layuimini-header-menu { + left: 205px !important + } + + .layui-layout-admin .layui-nav.layui-layout-right > li:not(.layuimini-setting) { + width: 40px !important; + } + + .layui-layout-admin .layui-nav.layui-layout-right > li:not(.layuimini-setting) a { + padding: 0 15px; + } + + .layuimini-all .layui-layout-admin .layui-body { + left: 0px !important; + } + + .layuimini-mini .layui-layout-admin .layuimini-menu-left, .layuimini-mini .layui-header .layuimini-logo { + left: 0; + transition: left .2s; + z-index: 1001 !important; + } + + .layuimini-all .layui-layout-admin .layuimini-menu-left, .layuimini-all .layui-header .layuimini-logo { + left: -200px; + transition: left .2s; + top: 0; + z-index: 1002; + } + + .layuimini-mini .layui-layout-admin .layui-body { + left: 0!important; + transition: left .2s; + top: 0; + z-index: 998; + } + + .layuimini-mini .layuimini-make { + display: block; + } + + .layuimini-multi-module .layuimini-header-content .layuimini-tool { + display: none; + } + + .layuimini-single-module .layuimini-header-content .layuimini-tool { + left: 15px; + } + + .layuimini-mini .layuimini-site-mobile { + display: none !important; + } + + .layuimini-site-mobile { + display: block !important; + position: fixed; + z-index: 100000; + bottom: 15px; + left: 15px; + width: 40px; + height: 40px; + line-height: 40px; + border-radius: 2px; + text-align: center; + background-color: rgba(0, 0, 0, .7); + color: #fff; + } + + .layuimini-header-content { + z-index: 997; + } + + /*修复UC之类的浏览器点击无效*/ + .layuimini-make { + cursor: pointer; + } + + .layuimini-site-mobile { + cursor: pointer; + } +} + +@media screen and (max-width: 550px){ + + /**头部右侧数据*/ + .layuimini-multi-module.layuimini-mini .layuimini-header-content .layui-layout-right { + display: none; + } +} diff --git a/ss-admin/src/main/resources/static/css/login.css b/ss-admin/src/main/resources/static/css/login.css new file mode 100644 index 0000000..f68a6d6 --- /dev/null +++ b/ss-admin/src/main/resources/static/css/login.css @@ -0,0 +1,275 @@ +.main-body { + top: 50%; + left: 50%; + position: absolute; + -webkit-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + -o-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + overflow: hidden; +} + +.login-main .login-bottom .center .item input { + display: inline-block; + width: 227px; + height: 22px; + padding: 0; + position: absolute; + border: 0; + outline: 0; + font-size: 14px; + letter-spacing: 0; +} + +.login-main .login-bottom .center .item .icon-1 { + background: url(/images/icon-login.png) no-repeat 1px 0; +} + +.login-main .login-bottom .center .item .icon-2 { + background: url(/images/icon-login.png) no-repeat -54px 0; +} + +.login-main .login-bottom .center .item .icon-3 { + background: url(/images/icon-login.png) no-repeat -106px 0; +} + +.login-main .login-bottom .center .item .icon-4 { + background: url(/images/icon-login.png) no-repeat 0 -43px; + position: absolute; + right: -10px; + cursor: pointer; +} + +.login-main .login-bottom .center .item .icon-5 { + background: url(/images/icon-login.png) no-repeat -55px -43px; +} + +.login-main .login-bottom .center .item .icon-6 { + background: url(/images/icon-login.png) no-repeat 0 -93px; + position: absolute; + right: -10px; + margin-top: 8px; + cursor: pointer; +} + +.login-main .login-bottom .tip .icon-nocheck { + display: inline-block; + width: 10px; + height: 10px; + border-radius: 2px; + border: solid 1px #9abcda; + position: relative; + top: 2px; + margin: 1px 8px 1px 1px; + cursor: pointer; +} + +.login-main .login-bottom .tip .icon-check { + margin: 0 7px 0 0; + width: 14px; + height: 14px; + border: none; + background: url(/images/icon-login.png) no-repeat -111px -48px; +} + +.login-main .login-bottom .center .item .icon { + display: inline-block; + width: 33px; + height: 22px; +} + +.login-main .login-bottom .center .item { + width: 288px; + height: 35px; + border-bottom: 1px solid #dae1e6; + margin-bottom: 35px; +} + +.login-main { + width: 428px; + position: relative; + float: left; +} + +.login-main .login-top { + height: 87px; + background-color: #148be4; + border-radius: 12px 12px 0 0; + font-family: SourceHanSansCN-Regular; + font-size: 30px; + font-weight: 400; + font-stretch: normal; + letter-spacing: 0; + color: #fff; + line-height: 87px; + text-align: center; + overflow: hidden; + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -ms-transform: rotate(0); + -o-transform: rotate(0); + transform: rotate(0); +} + +.login-main .login-top .bg1 { + display: inline-block; + width: 74px; + height: 74px; + background: #fff; + opacity: .1; + border-radius: 0 74px 0 0; + position: absolute; + left: 0; + top: 43px; +} + +.login-main .login-top .bg2 { + display: inline-block; + width: 94px; + height: 94px; + background: #fff; + opacity: .1; + border-radius: 50%; + position: absolute; + right: -16px; + top: -16px; +} + +.login-main .login-bottom { + width: 428px; + background: #fff; + border-radius: 0 0 12px 12px; + padding-bottom: 23px; +} + +.login-main .login-bottom .center { + width: 288px; + margin: 0 auto; + padding-top: 30px; + padding-bottom: 0px; + position: relative; +} + +.login-main .login-bottom .tip { + clear: both; + height: 16px; + line-height: 16px; + width: 288px; + margin: 0 auto; +} + +body { + background: url(/images/bg-login.jpg) 0% 0% / cover no-repeat; + position: static; + font-size: 14px; +} + +input::-webkit-input-placeholder { + color: #a6aebf; +} + +input::-moz-placeholder { /* Mozilla Firefox 19+ */ + color: #a6aebf; +} + +input:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ + color: #a6aebf; +} + +input:-ms-input-placeholder { /* Internet Explorer 10-11 */ + color: #a6aebf; +} + +input:-webkit-autofill { /* 取消Chrome记住密码的背景颜色 */ + -webkit-box-shadow: 0 0 0 1000px white inset !important; +} + +html { + height: 100%; +} + +.login-main .login-bottom .tip { + clear: both; + height: 16px; + line-height: 16px; + width: 288px; + margin: 0 auto; +} + +.login-main .login-bottom .tip .login-tip { + font-family: MicrosoftYaHei; + font-size: 14px; + font-weight: 400; + font-stretch: normal; + letter-spacing: 0; + color: #9abcda; + cursor: pointer; +} + +.login-main .login-bottom .tip .forget-password { + font-stretch: normal; + letter-spacing: 0; + color: #1391ff; + text-decoration: none; + position: absolute; + right: 62px; +} + +.login-main .login-bottom .login-btn { + width: 288px; + height: 40px; + background-color: #1E9FFF; + border-radius: 16px; + margin: 24px auto 0; + text-align: center; + line-height: 40px; + color: #fff; + font-size: 14px; + letter-spacing: 0; + cursor: pointer; + border: none; +} + +.login-main .login-bottom .center .item .validateImg { + position: absolute; + right: 1px; + cursor: pointer; + height: 36px; + border: 1px solid #e6e6e6; +} + +.footer { + left: 0; + bottom: 0; + color: #fff; + width: 100%; + position: absolute; + text-align: center; + line-height: 30px; + padding-bottom: 10px; + text-shadow: #000 0.1em 0.1em 0.1em; + font-size: 14px; +} + +.padding-5 { + padding: 5px !important; +} + +.footer a, .footer span { + color: #fff; +} + +@media screen and (max-width: 428px) { + .login-main { + width: 360px !important; + } + + .login-main .login-top { + width: 360px !important; + } + + .login-main .login-bottom { + width: 360px !important; + } +} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/css/login2/admin.css b/ss-admin/src/main/resources/static/css/login2/admin.css new file mode 100644 index 0000000..f323f31 --- /dev/null +++ b/ss-admin/src/main/resources/static/css/login2/admin.css @@ -0,0 +1,2 @@ +/** EasyWeb iframe v3.1.8 date:2020-05-04 License By http://easyweb.vip */ +*{font-family:"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif}body{color:#595959;background-color:#f5f7f9}.layui-layout-body{overflow:auto}.layui-layout-admin{position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden;-webkit-transition:left .3s,right .3s;transition:left .3s,right .3s}.layui-layout-admin .layui-header{position:absolute;top:0;left:0;right:0;height:50px;background-color:#fff;box-shadow:0 1px 0 0 rgba(0,0,0,.03);z-index:999}.layui-layout-admin .layui-header .layui-logo{color:#ddd;width:235px;line-height:50px;background-color:#191a23;box-shadow:1px 2px 2px 0 rgba(0,0,0,.05);position:relative;vertical-align:top;white-space:nowrap;display:inline-block;-webkit-transition:width .3s;transition:width .3s;overflow:hidden}.layui-layout-admin .layui-header .layui-logo img{height:28px;vertical-align:middle}.layui-layout-admin .layui-header .layui-logo cite{font-style:normal;vertical-align:middle}.layui-layout-admin .layui-header .layui-layout-left{padding:0;vertical-align:top;display:inline-block;position:static!important}.layui-layout-admin .layui-header .layui-layout-right{padding:0}.layui-layout-admin .layui-header .layui-nav .layui-this:after,.layui-layout-admin .layui-header .layui-nav-bar{height:2px;top:0!important;background-color:#191a23}.layui-layout-admin .layui-header .layui-nav .layui-nav-item{line-height:50px;vertical-align:top}.layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child{top:55px}.layui-layout-admin .layui-header .layui-nav-item .layui-icon{font-size:16px}.layui-layout-admin .layui-header a{color:#595959;padding:0 15px;cursor:pointer}.layui-layout-admin .layui-header a:hover{color:#595959}.layui-layout-admin .layui-header .layui-nav-child a{color:#595959;text-align:center}.layui-layout-admin .layui-header .layui-nav .layui-nav-more{border-color:#8c8c8c transparent transparent}.layui-layout-admin .layui-header .layui-nav .layui-nav-mored{border-color:transparent transparent #8c8c8c}.layui-layout-admin .layui-header .layui-nav-img{width:26px;height:26px;margin-right:2px;vertical-align:middle}.layui-layout-admin .layui-header .layui-nav-img+cite{margin-right:3px;vertical-align:middle}.layui-layout-admin .layui-header .layui-badge-dot{right:8px;margin:-10px 0 0 0}.layui-layout-admin .layui-body{position:absolute;left:235px;top:50px;z-index:auto;overflow:auto;-webkit-transition:left .3s;transition:left .3s;-webkit-overflow-scrolling:touch}.admin-iframe{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%}.layui-fluid{padding:15px}.layui-layout-admin .layui-footer{position:absolute;left:235px;background:#fff;box-sizing:border-box;border-top:1px solid #f5f7f9;-webkit-transition:left .3s;transition:left .3s;overflow:hidden}.close-footer .layui-layout-admin .layui-footer{display:none}.close-footer .layui-layout-admin .layui-body{bottom:0}.layui-layout-admin .layui-side{position:absolute;top:50px;width:235px;background-color:#191a23;box-shadow:1px 2px 2px 0 rgba(0,0,0,.05);-webkit-transition:width .3s;transition:width .3s;-webkit-user-select:none;user-select:none;z-index:1000}.layui-layout-admin .layui-side .layui-side-scroll{width:255px;-webkit-transition:width .3s;transition:width .3s}.layui-layout-admin .layui-side .layui-nav{width:235px;background-color:transparent;-webkit-transition:width .3s;transition:width .3s}.layui-layout-admin .layui-side>.layui-side-scroll>.layui-nav:first-child{margin-top:10px}.layui-layout-admin .layui-side .layui-nav .layui-nav-item>a{cursor:pointer;padding-top:5px;padding-bottom:5px}.layui-layout-admin .layui-side .layui-nav .layui-nav-item a{-webkit-transition:color .3s,background-color .3s;transition:color .3s,background-color .3s}.layui-layout-admin .layui-side .layui-nav .layui-nav-more{right:15px}.layui-layout-admin .layui-side .layui-nav .layui-nav-item>.layui-nav-child{position:static}.layui-layout-admin .layui-side .layui-nav .layui-nav-item .layui-nav-child a{padding-left:50px;cursor:pointer}.layui-layout-admin .layui-side .layui-nav .layui-nav-item .layui-nav-child .layui-nav-child a{padding-left:70px}.layui-layout-admin .layui-side .layui-nav .layui-nav-item .layui-nav-child .layui-nav-child .layui-nav-child a{padding-left:90px}.layui-layout-admin .layui-side .layui-nav .layui-nav-item .layui-nav-child .layui-nav-child .layui-nav-child .layui-nav-child a{padding-left:110px}@media screen and (min-width:769px){.layui-layout-admin.admin-nav-mini .layui-header .layui-logo{width:60px}.layui-layout-admin.admin-nav-mini .layui-header .layui-logo cite{display:none}.layui-layout-admin.admin-nav-mini .layui-header .layui-icon-shrink-right:before{content:"\e66b"}.layui-layout-admin.admin-nav-mini .layui-body,.layui-layout-admin.admin-nav-mini .layui-footer{left:60px}.layui-layout-admin.admin-nav-mini .layui-side,.layui-layout-admin.admin-nav-mini .layui-side .layui-nav{width:60px}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .layui-nav-item>a{overflow:visible}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .layui-nav-item>a>cite,.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .layui-nav-item>a .layui-nav-more,.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .layui-nav-itemed>.layui-nav-child{display:none!important}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav li.layui-nav-itemed>a{background:rgba(0,0,0,.3)}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .layui-nav-item>a>.layui-icon{font-size:16px;-webkit-transition:font-size .3s;transition:font-size .3s}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child{position:fixed;top:60px;left:60px;padding:5px;min-width:150px;display:block!important;background:transparent!important}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child:before{content:'';position:absolute;right:5px;left:5px;bottom:0;top:0;border-radius:4px;background:#191a23;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child dd:first-child>.layui-nav-child{margin-top:-5px}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child dd:last-child>.layui-nav-child.show-top{margin-top:5px}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child>dd>a{padding:0 20px!important}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child>dd>a .layui-nav-more{border-color:transparent transparent transparent rgba(255,255,255,.7);right:7px;margin-top:-6px}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav.arrow2 .admin-nav-hover>.layui-nav-child>dd>a .layui-nav-more,.layui-layout-admin.admin-nav-mini .layui-side .layui-nav.arrow3 .admin-nav-hover>.layui-nav-child>dd>a .layui-nav-more{-o-transform:rotate(0deg);-ms-transform:rotate(0deg);-moz-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg);width:6px;height:10px;right:10px;margin-top:-5px;font-weight:600}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav.arrow2 .admin-nav-hover>.layui-nav-child>dd>a .layui-nav-more:before,.layui-layout-admin.admin-nav-mini .layui-side .layui-nav.arrow3 .admin-nav-hover>.layui-nav-child>dd>a .layui-nav-more:before{content:"\e602";left:-4px;top:-2px}.layui-layout-admin.admin-nav-mini .layui-side .layui-nav.arrow3 .admin-nav-hover>.layui-nav-child>dd>a .layui-nav-more:before{-o-transform:rotate(0deg);-ms-transform:rotate(0deg);-moz-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@media screen and (max-width:768px){.layui-layout-admin{left:-235px}.layui-layout-admin .layui-side,.layui-layout-admin .layui-header .layui-logo{box-shadow:none!important}.layui-layout-admin .layui-header .layui-icon-shrink-right:before{content:"\e66b"}.layui-layout-admin.admin-nav-mini{left:0;right:-235px;position:fixed}.layui-layout-admin.admin-nav-mini .layui-header .layui-icon-shrink-right:before{content:"\e668"}.layui-layout-admin.admin-nav-mini .layui-side,.layui-layout-admin.admin-nav-mini .layui-header .layui-logo{box-shadow:1px 0 2px 0 rgba(0,0,0,.05)}.layui-layout-admin.admin-nav-mini .site-mobile-shade{position:absolute;top:0;right:0;bottom:0;left:235px;background-color:rgba(0,0,0,.25);-webkit-transition:background-color .3s;transition:background-color .3s;cursor:pointer;z-index:1000}}.ew-anim-drop-in{-webkit-animation:ewTransitionDropIn .3s ease-in-out;animation:ewTransitionDropIn .3s ease-in-out;-webkit-transform-origin:0 0;transform-origin:0 0}@-webkit-keyframes ewTransitionDropIn{from{opacity:0;-webkit-transform:scale(0.8)}to{opacity:1;-webkit-transform:scale(1)}}@keyframes ewTransitionDropIn{from{opacity:0;transform:scale(0.8)}to{opacity:1;transform:scale(1)}}.layui-nav-tree .layui-nav-bar{display:none}.layui-nav-tree>.layui-nav-item>a:before{content:"";position:absolute;top:0;left:0;bottom:100%;width:4px;background-color:#009688;-webkit-transition:all .3s ease;transition:all .3s ease}.layui-nav-tree>.layui-nav-item:hover>a:before{bottom:0}.layui-nav-tree .layui-nav-item a:hover{background-color:transparent}.layui-nav-tree .layui-this>a:hover{background-color:#009688}.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-this{background:transparent}.layui-nav-tree .layui-nav-item .layui-nav-child{padding:5px 0;background-color:rgba(0,0,0,.3)!important}.layui-nav-tree.arrow2 .layui-nav-more{font-family:layui-icon!important;font-size:12px;font-weight:600;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overflow:hidden;line-height:normal;border:0;margin:-3px 0 0 0;padding:0;width:10px;height:6px;top:50%;display:inline-block;-webkit-transition:all .3s ease;transition:all .3s ease}.layui-nav-tree.arrow2 .layui-nav-more:before{content:"\e61a";position:absolute;right:-1px;top:-4px}.layui-nav-tree.arrow2 .layui-nav-itemed>a>.layui-nav-more{-ms-transform:rotate(-180deg);-moz-transform:rotate(-180deg);-webkit-transform:rotate(-180deg);-o-transform:rotate(-180deg);transform:rotate(-180deg)}.layui-nav-tree.arrow3 .layui-nav-more{font-family:layui-icon!important;font-size:12px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overflow:hidden;line-height:normal;border:0;margin:-5px 0 0 0;padding:0;width:10px;height:10px;top:50%;display:inline-block;-webkit-transition:all .3s ease;transition:all .3s ease}.layui-nav-tree.arrow3 .layui-nav-more:before{content:"\e654";position:absolute;top:-2px;left:-1px}.layui-nav-tree.arrow3 .layui-nav-itemed>a>.layui-nav-more{-ms-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}.layui-nav-tree.arrow3 .layui-nav-itemed>a>.layui-nav-more:before{content:'';width:8px;height:2px;background-color:rgba(255,255,255,.7);top:4px;left:1px;-ms-transform:rotate(45deg);-moz-transform:rotate(45deg);-webkit-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.layui-layout-admin .layui-body>.layui-tab{position:absolute;top:0;left:0;right:0;bottom:0;margin:0}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-content{position:absolute;left:0;right:0;bottom:0;top:40px;padding:0}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-content>.layui-tab-item{position:absolute;bottom:0;right:0;top:0;left:0;overflow:auto;-webkit-overflow-scrolling:touch;display:block;visibility:hidden;opacity:0;filter:Alpha(opacity=0)}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-content>.layui-tab-item.layui-show{visibility:visible;opacity:1;filter:Alpha(opacity=100)}.layui-layout-admin.admin-side-flexible .layui-body>.layui-tab>.layui-tab-content>.layui-tab-item{display:none}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-title{height:40px;line-height:40px;padding:0 80px 0 40px;background-color:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.1);position:absolute;top:0;left:0;right:0;border:0;overflow:hidden;-webkit-transition:none;transition:none;z-index:998}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li{min-width:auto;max-width:160px;line-height:40px;padding:0 30px 0 15px;border-right:1px solid #f6f6f6;overflow:hidden;text-overflow:ellipsis;vertical-align:top;-webkit-transition:background-color .2s;transition:background-color .2s}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this,.layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li:hover{background-color:#f6f6f6}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this:after{height:2px;border:0;border-radius:0;background-color:#191a23}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li:first-child{padding:0 15px}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li cite{font-style:normal}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-title .layui-tab-bar{display:none}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li .layui-tab-close{width:16px;height:16px;line-height:16px;font-size:12px;border-radius:50%;position:absolute;top:12px;right:8px;-webkit-transition:background-color .2s,color .2s;transition:background-color .2s,color .2s}.layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li:first-child .layui-tab-close{display:none}.admin-tabs-control{position:absolute;top:0;width:40px;height:40px;line-height:40px;background-color:#fff;border-left:1px solid #f6f6f6;-webkit-transition:background-color .2s;transition:background-color .2s;text-align:center;cursor:pointer;z-index:998}.admin-tabs-control:hover{background-color:#f6f6f6}.admin-tabs-control.layui-icon-prev{left:0;border-left:none;border-right:1px solid #f6f6f6}.admin-tabs-control.layui-icon-next{right:40px}.admin-tabs-control.layui-icon-down{right:0}.admin-tabs-control>.layui-nav,.admin-tabs-control>.layui-nav .layui-nav-item{position:absolute;top:0;left:0;padding:0;width:100%;height:100%;background:transparent}.admin-tabs-control>.layui-nav .layui-nav-child{right:0;top:40px;left:auto}.admin-tabs-control>.layui-nav .layui-nav-child a{color:#595959}.admin-tabs-control>.layui-nav .layui-nav-bar,.admin-tabs-control>.layui-nav .layui-nav-more{display:none}.layui-body-header{padding:0 20px;height:40px;line-height:40px;background-color:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.1);box-sizing:border-box;position:absolute;left:0;right:0;z-index:998;display:none}.layui-body-header.show{display:block}.layui-body-header-title{padding-left:6px;border-left:4px solid #009688}.layui-body-header.show+div{position:absolute;left:0;right:0;top:40px;bottom:0;overflow:auto;-webkit-overflow-scrolling:touch}.hide-body-title .layui-body-header.show{display:none}.hide-body-title .layui-body-header.show+div{top:0}.layui-layout-admin .layui-body>.page-loading,.layui-layout-admin .layui-body>.layui-tab>.layui-tab-content>.layui-tab-item>.page-loading,.layui-layout-admin .layui-body>div>iframe[lay-id]+.page-loading{z-index:997}.layui-layer.layui-layer-adminRight{bottom:0;top:50px!important;border:none!important;box-shadow:1px 1px 50px rgba(0,0,0,.3)!important;overflow:auto}.layui-layer.layui-layer-adminRight>.layui-layer-content,.layui-layer.layui-layer-adminRight>.layui-layer-content>iframe{height:100%!important}.layui-layer.layui-layer-adminRight>.layui-layer-title+.layui-layer-content{position:absolute;top:43px;left:0;right:0;bottom:0;height:auto!important}.layui-anim-rl{-webkit-animation-name:layui-rl;animation-name:layui-rl}@-webkit-keyframes layui-rl{from{-webkit-transform:translate3d(100%,0,0)}to{-webkit-transform:translate3d(0,0,0)}}@keyframes layui-rl{from{transform:translate3d(100%,0,0)}to{transform:translate3d(0,0,0)}}.layui-anim-lr,.layui-anim-rl.layer-anim-close{-webkit-animation-name:layui-lr;animation-name:layui-lr}@-webkit-keyframes layui-lr{from{-webkit-transform:translate3d(0,0,0);opacity:1}to{-webkit-transform:translate3d(100%,0,0);opacity:1}}@keyframes layui-lr{from{transform:translate3d(0,0,0)}to{transform:translate3d(100%,0,0)}}.layui-layer.layui-layer-admin{border:none!important;box-shadow:1px 1px 50px rgba(0,0,0,.3)!important}.layui-layer.layui-layer-admin .layui-layer-title{color:#fff;height:50px;line-height:50px;background-color:#191a23;border:0}.layui-layer.layui-layer-admin .layui-layer-setwin{top:17px}.layui-layer.layui-layer-admin .layui-layer-setwin a{color:#fff;font-size:16px;font-style:normal;font-family:layui-icon!important;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-layer.layui-layer-admin .layui-layer-setwin .layui-layer-close1{background:0;margin-top:-1px}.layui-layer.layui-layer-admin .layui-layer-setwin .layui-layer-close1:before{content:"\1006"}.layui-layer.layui-layer-admin .layui-layer-setwin .layui-layer-min cite{background-color:#ddd}.layui-layer.layui-layer-admin .layui-layer-setwin .layui-layer-max{font-size:14px;padding-top:1px;background:0}.layui-layer.layui-layer-admin .layui-layer-setwin .layui-layer-max:before{content:"\e622"}.layui-layer.layui-layer-admin .layui-layer-setwin .layui-layer-maxmin:before{content:"\e758"}.layui-layer.layui-layer-admin .layui-layer-btn{padding-bottom:15px}.layui-layer.layui-layer-admin .layui-layer-btn .layui-layer-btn0{border-color:#009688;background-color:#009688}.layui-layer.layui-layer-admin .layui-layer-btn a{height:34px;line-height:34px}.layui-layer-admin{max-width:100%}.layui-layer-iframe .layui-layer-content{overflow:auto;-webkit-overflow-scrolling:touch}@media screen and (max-width:768px){.layui-layer-admin{max-width:98%;max-width:-webkit-calc(100% - 30px);max-width:-moz-calc(100% - 30px);max-width:calc(100% - 30px);width:max-content;left:0!important;right:0!important;margin:auto!important;margin-bottom:15px!important}.layui-layer-admin[area]{max-width:100%;margin-bottom:0!important}}body .layui-layer-msg{border:0;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,0.1)}body .layui-layer-load{background:transparent}.page-loading{position:absolute;display:block;width:100%;height:100%;top:0;left:0;right:0;bottom:0;z-index:19891017;background-color:#fff}body>.page-loading{position:fixed;background-color:#f5f7f9}.layui-layout-admin>.layui-body>.layui-tab>.layui-tab-content>.layui-tab-item>.page-loading,.layui-layout-admin>.layui-body>.page-loading,.layui-layout-admin>.layui-body>div>iframe[lay-id]+.page-loading{background-color:#f5f7f9}.layui-layout-admin>.layui-body>.layui-body-header.show+div+.page-loading{top:40px;height:auto}.page-no-scroll{overflow-x:hidden!important;overflow-y:hidden!important;min-height:80px}.rubik-loader,.ball-loader,.signal-loader,.layui-loader{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.ball-loader>span,.signal-loader>span{background-color:#4aca85;display:inline-block}.ball-loader>span:nth-child(1),.ball-loader.sm>span:nth-child(1),.signal-loader>span:nth-child(1),.signal-loader.sm>span:nth-child(1){-webkit-animation-delay:0s;animation-delay:0s}.ball-loader>span:nth-child(2),.ball-loader.sm>span:nth-child(2),.signal-loader>span:nth-child(2),.signal-loader.sm>span:nth-child(2){-webkit-animation-delay:.1s;animation-delay:.1s}.ball-loader>span:nth-child(3),.ball-loader.sm>span:nth-child(3),.signal-loader>span:nth-child(3),.signal-loader.sm>span:nth-child(3){-webkit-animation-delay:.15s;animation-delay:.15s}.ball-loader>span:nth-child(4),.ball-loader.sm>span:nth-child(4),.signal-loader>span:nth-child(4),.signal-loader.sm>span:nth-child(4){-webkit-animation-delay:.2s;animation-delay:.2s}.rubik-loader{width:64px;height:64px;background-image:url(img/ic_loading.gif);background-repeat:no-repeat;background-position:center;background-size:contain}.rubik-loader.sm{width:50px;height:50px}.ball-loader>span{width:20px;height:20px;margin:0 3px;border-radius:50%;-webkit-transform:scale(0);-ms-transform:scale(0);transform:scale(0);-webkit-animation:1s ball-load ease-in-out infinite;animation:ball-load 1s ease-in-out infinite}@-webkit-keyframes ball-load{0%{-webkit-transform:scale(0)}50%{-webkit-transform:scale(1)}100%{-webkit-transform:scale(0)}}@keyframes ball-load{0%{transform:scale(0)}50%{transform:scale(1)}100%{transform:scale(0)}}.ball-loader.sm>span{width:15px;height:15px;margin:0 2px}.signal-loader{width:50px;height:22px}.signal-loader>span{width:8px;height:0;position:absolute;bottom:0;left:0;margin:0;-webkit-animation:signal-load 1s infinite;animation:signal-load 1s infinite}.signal-loader>span:nth-child(2){left:14px}.signal-loader>span:nth-child(3){left:28px}.signal-loader>span:nth-child(4){left:42px}@-webkit-keyframes signal-load{0%{height:0}50%{height:22px}100%{height:0}}@keyframes signal-load{0%{height:0}50%{height:22px}100%{height:0}}.signal-loader.sm{width:32px;height:15px}.signal-loader.sm>span{width:5px;-webkit-animation:signal-load-sm 1s infinite;animation:signal-load-sm 1s infinite}.signal-loader.sm>span:nth-child(2){left:9px}.signal-loader.sm>span:nth-child(3){left:18px}.signal-loader.sm>span:nth-child(4){left:27px}@-webkit-keyframes signal-load-sm{0%{height:0}50%{height:15px}100%{height:0}}@keyframes signal-load-sm{0%{height:0}50%{height:15px}100%{height:0}}.layui-loader .layui-icon{font-size:36px;color:#bbb}.layui-loader.sm .layui-icon{font-size:30px}.layui-form.toolbar .layui-form-item,.layui-form.toolbar .layui-form-item .layui-inline>.layui-input-inline{margin-bottom:0}.layui-form.toolbar .layui-form-item .layui-inline{margin-bottom:10px}.toolbar+.layui-table,.layui-card-body>.layui-table,.toolbar+table+.layui-table-view,.layui-card-body>.layui-table-view,.toolbar+table+.ew-tree-table{margin:0}.mr0,.layui-form.toolbar .layui-form-item .layui-inline>.layui-input-inline{margin-right:0!important}.w-auto{width:auto!important}.model-form{padding:25px 30px 0 0}.model-form.no-padding{padding:0}.model-form .model-form-body{overflow-y:auto;padding:25px 30px 0 0;max-height:calc(100vh - 180px)}.model-form.no-padding .model-form-footer{padding-top:10px;padding-right:30px}.layui-form.model-form>.layui-form-item:last-child{margin-bottom:0;padding-bottom:20px}.layui-form-required:before{content:"*";display:inline-block;font-family:SimSun;margin-right:4px;font-size:14px;line-height:1;color:#ed4014}.layui-input,.layui-textarea{color:#595959}.layui-form-select .layui-input{padding-right:0}.layui-form-select-top .layui-form-select>dl{top:auto;bottom:42px}.ew-select-fixed .layui-form-selected dl{position:fixed;min-width:auto;bottom:auto;right:auto}body .layui-form-checked[lay-skin=primary] i,body .layui-form-checked[lay-skin=primary]:hover i{color:#fff}body .layui-form-checkbox[lay-skin=primary] span,body .layui-form-checkbox[lay-skin=primary]:hover span{background-color:transparent}body .layui-form-danger+.layui-form-select .layui-input,body .layui-input.layui-form-danger:focus,body .layui-textarea.layui-form-danger:focus{border-color:#ff5722!important}body .layui-laypage input.layui-input{height:30px;line-height:30px}body .layui-table-page .layui-laypage input.layui-input{height:26px;line-height:26px}body .layui-form-onswitch em{margin-left:3px;margin-right:18px}.layui-btn{-webkit-transition:background-color .2s;transition:background-color .2s}body .layui-btn.layui-btn-radius{border-radius:100px}.layui-btn-primary{color:#595959;border-color:#e6e6e6}.layui-btn-primary:hover{border-color:#bbb}.layui-btn-group .layui-btn-primary:hover{border-color:#e6e6e6}.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid #e6e6e6}body .layui-btn.layui-btn-disabled,body .layui-transfer-active .layui-btn.layui-btn-disabled{background-color:#fbfbfb!important;border-color:#e6e6e6!important;color:#c9c9c9!important}body .layui-btn.layui-btn-primary{background-color:#fff}body .layui-btn.layui-btn-normal{background-color:#1e9fff}body .layui-btn.layui-btn-warm{background-color:#ffb800}body .layui-btn.layui-btn-danger{background-color:#ff5722}.layui-btn-group>.layui-btn+.layui-btn{border-radius:0}.layui-btn-group>.layui-btn:last-child{border-top-right-radius:2px;border-bottom-right-radius:2px}body .layui-transfer-active .layui-btn{background-color:#5fb878!important;border-color:#5fb878!important;color:#fff!important}.btn-circle{width:50px;height:50px;line-height:50px;border-radius:50%;background:#009688;position:fixed;right:15px;bottom:15px;color:#fff;text-align:center;box-shadow:0 0 8px rgba(0,0,0,.2);cursor:pointer}.btn-circle:hover{color:#fff;opacity:.8}.btn-circle .layui-icon{font-size:24px}.icon-date,.date-icon{background-image:url(img/icon_date.png);background-repeat:no-repeat;background-position:right center;padding-right:28px}.icon-search{background-image:url(img/icon_search.png);background-repeat:no-repeat;background-position:right center;padding-right:26px}span.icon-text>.layui-icon,a.icon-text>.layui-icon,.layui-form-label.icon-text>.layui-icon{font-size:14px;margin:0 2px}.layui-btn.icon-btn{padding:0 10px}.layui-btn.layui-btn-sm.icon-btn{padding:0 6px}.bg-white,html.bg-white>body{background-color:white}[ew-href],[lay-tips]{cursor:pointer}.inline-block{display:inline-block}.pull-right{float:right}.pull-left{float:left}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-primary,.layui-link{color:#009688!important}.text-success{color:#5fb878!important}.text-warning{color:#ffb800!important}.text-danger{color:#ff5722!important}.text-info{color:#01aaed!important}.text-muted{color:#c2c2c2!important}.layui-text a:not(.layui-btn){color:#2d8cf0;cursor:pointer}.layui-text a:not(.layui-btn):hover{text-decoration:none}.ew-console-wrapper .layui-card{box-shadow:none;border-radius:4px}.layui-card-header{color:#595959}.lay-big-font{font-size:36px;line-height:36px;padding:5px 0 10px;overflow:hidden;white-space:nowrap;word-break:break-all;text-overflow:ellipsis}.no-scrollbar{overflow-x:hidden!important;overflow-y:hidden!important}input.layui-disabled,input.layui-disabled:hover,textarea.layui-disabled,textarea.layui-disabled:hover{color:#595959!important;background-color:#f6f6f6}.layui-input::-webkit-input-placeholder,.layui-textarea::-webkit-input-placeholder{color:#ccc}.layui-input::-moz-placeholder,.layui-textarea::-moz-placeholder{color:#ccc}.layui-input::-ms-input-placeholder,.layui-textarea::-ms-input-placeholder{color:#ccc}.dropdown-menu{display:inline-block}.dropdown-menu .dropdown-menu-nav{display:none}.dropdown-menu+.dropdown-menu,.layui-btn+.dropdown-menu,.dropdown-menu+.layui-btn{margin-left:10px}::-webkit-scrollbar{width:10px;height:10px;background:transparent}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{border-radius:5px;background-color:#c1c1c1}::-webkit-scrollbar-thumb:hover{background-color:#a8a8a8}.mini-bar::-webkit-scrollbar{width:6px;height:6px}.mini-bar::-webkit-scrollbar-thumb{border-radius:3px}@media screen and (max-width:768px){::-webkit-scrollbar{width:4px;height:4px}::-webkit-scrollbar-thumb{border-radius:0}}#ew-map-select-map{height:450px}#ew-map-select-pois{height:450px;overflow-x:hidden;overflow-y:auto}.ew-map-select-search-list-item{padding:10px 30px 10px 15px;border-bottom:1px solid #e8e8e8;cursor:pointer;position:relative}.ew-map-select-search-list-item:hover{background:#f2f2f2}.ew-map-select-search-list-item:last-child{border-bottom:0}.ew-map-select-search-list-item .ew-map-select-search-list-item-title{font-size:14px;color:#262626}.ew-map-select-search-list-item .ew-map-select-search-list-item-address{font-size:12px;color:#595959;padding-top:5px}.ew-map-select-search-list-item-icon-ok{position:absolute;right:15px;top:50%;transform:translateY(-50%)}.ew-map-select-search-list-item-icon-ok .layui-icon{color:#3b74ff}.ew-map-select-tool{padding:5px 15px;box-shadow:0 1px 0 0 rgba(0,0,0,.05)}#ew-map-select-center-img{position:absolute;bottom:50%;left:50%;width:26px;margin-left:-13px}#ew-map-select-center-img2{position:absolute;left:50%;top:50%;font-size:12px;display:inline-block;margin-left:-6px;margin-top:-7px;color:#3b74ff}.bounceInDown{animation:bounceInDown 500ms;animation-direction:alternate;-webkit-animation:bounceInDown 500ms;-webkit-animation-direction:alternate}@-webkit-keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-transition-timing-function:cubic-bezier(.215,.61,.355,1)}0%,to{-webkit-transform:translate3d(0,0,0)}25%{-webkit-transform:translate3d(0,-30px,0)}50%{-webkit-transform:translate3d(0,-15px,0)}75%{-webkit-transform:translate3d(0,-4px,0)}}@keyframes bounceInDown{0%,60%,75%,90%,to{transition-timing-function:cubic-bezier(.215,.61,.355,1)}0%,to{transform:translate3d(0,0,0)}25%{transform:translate3d(0,-10px,0)}50%{transform:translate3d(0,-20px,0)}75%{transform:translate3d(0,-10px,0)}}#ew-map-select-tips{position:absolute;z-index:999;background:#fff;max-height:430px;overflow:auto;top:48px;left:56px;width:280px;box-shadow:0 2px 4px rgba(0,0,0,.12);border:1px solid #d2d2d2}#ew-map-select-tips .ew-map-select-search-list-item{padding:10px 15px 10px 35px}.ew-map-select-search-list-item-icon-search{position:absolute;left:10px;top:50%;transform:translateY(-50%)}.ew-map-select-search-list-item-icon-search .layui-icon{color:#8c8c8c}.table-tool-mini .layui-table-view{position:relative}.table-tool-mini .layui-table-tool{position:absolute;min-height:unset;height:auto;padding:3px 10px;width:auto;top:-38px;right:-1px;border-top-right-radius:8px;border-top-left-radius:8px;border:1px solid #e6e6e6;border-bottom:0}.table-tool-mini .layui-table-tool .layui-table-tool-temp{padding-right:0;display:inline-block}.table-tool-mini .layui-table-tool .layui-table-tool-self{position:static;display:inline-block}.table-tool-mini .layui-table-tool .layui-table-tool-self .layui-inline[lay-event]:first-child{margin:0}.table-tool-mini.full-table .layui-table-tool{top:-35px;height:1px;padding:0 10px;background:transparent;border:0}.table-tool-mini.full-table .layui-table-tool:before{content:"";position:absolute;top:-3px;right:0;left:0;height:36px;background-color:#f2f2f2;border-top-right-radius:8px;border-top-left-radius:8px;border:1px solid #e6e6e6;border-bottom:0}@media screen and (max-width:768px){.layui-laydate-range{left:0!important;top:0!important;right:0!important;margin:10px auto!important;max-width:95%}.layui-laydate-range .layui-laydate-main,.layui-laydate-range .layui-laydate-content table{width:100%}.layui-laydate-range .laydate-main-list-0 .laydate-next-m,.layui-laydate-range .laydate-main-list-0 .laydate-next-y,.layui-laydate-range .laydate-main-list-1 .laydate-prev-m,.layui-laydate-range .laydate-main-list-1 .laydate-prev-y{display:inline-block!important}.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-top:1px solid #e2e2e2}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content{border-left:none!important}.layui-laydate-range .laydate-time-list ol li{padding-left:0!important;text-align:center}.layui-laydate-range .laydate-time-list ol{overflow:auto!important}}.layui-tree-spread>div>div>span>.layui-tree-iconArrow:after{border-color:#c0c4cc transparent transparent transparent;top:6px;left:0}.layui-tree .layui-tree-iconArrow:after{transition:none}.ew-tb-cell-ck .layui-form-checkbox[lay-skin=primary]{padding-left:22px}.ew-tb-cell-ck .layui-form-checkbox[lay-skin=primary] span{padding-right:5px}.ew-field-group>.layui-elem-field{border-bottom:0;margin:0}.ew-field-group>.ew-field-box{border:1px solid #e6e6e6;padding:10px 15px;border-top:0}body .layui-elem-quote.layui-quote-nm{border-color:#e6e6e6}.layui-card>.layui-tab-brief>.layui-tab-title li{padding:0 5px;margin:0 10px;line-height:43px;height:43px;transition:color .2s;-webkit-transition:color .2s}.layui-card>.layui-tab-brief>.layui-tab-title li:after{height:43px}.layui-card>.layui-tab-brief>.layui-tab-title{border-bottom-color:#f6f6f6;height:42px;transition:none;-webkit-transition:none}.layui-card>.layui-tab-brief>.layui-tab-content{padding:10px 15px}.layui-tab.layui-tab-vertical{position:relative}.layui-tab.layui-tab-vertical:after{content:"";clear:both;display:block}.layui-tab.layui-tab-vertical>.layui-tab-title{width:130px;height:auto;border:0;border-right:1px solid #e9e9e9;box-sizing:border-box;padding:10px 0;float:left}.layui-tab.layui-tab-vertical>.layui-tab-title>li{display:block;margin-right:-1px;border-right:2px solid transparent;white-space:normal;line-height:normal;padding:10px 20px;text-align:right}.layui-tab.layui-tab-vertical>.layui-tab-title>li.layui-this{border-right:2px solid #5fb878;color:#5fb878}.layui-tab.layui-tab-vertical>.layui-tab-title>li.layui-this:after{display:none}.layui-tab.layui-tab-vertical>.layui-tab-title>li>.layui-icon{font-size:14px;margin-right:5px}.layui-tab.layui-tab-vertical>.layui-tab-content{margin-left:130px}.layui-tab.layui-tab-vertical.layui-tab-vertical-right>.layui-tab-title{float:right;border-right:0;border-left:1px solid #e9e9e9}.layui-tab.layui-tab-vertical.layui-tab-vertical-right>.layui-tab-content{margin-left:0;margin-right:130px}.layui-tab.layui-tab-vertical.layui-tab-vertical-right>.layui-tab-title>li{text-align:left;border-left:2px solid transparent;border-right:0}.layui-tab.layui-tab-vertical.layui-tab-vertical-right>.layui-tab-title>li.layui-this{border-left:2px solid #5fb878}.layui-tab.layui-tab-vertical.layui-tab-vertical-full>.layui-tab-title{position:absolute;top:0;left:0;right:auto;min-height:100%}.layui-tab.layui-tab-vertical.layui-tab-vertical-right.layui-tab-vertical-full>.layui-tab-title{right:0;left:auto}.ew-btn-loading{opacity:.8;pointer-events:none;font-size:0!important}.ew-btn-loading *{display:none!important}.ew-btn-loading>.ew-btn-loading-text{font-size:14px!important;display:inline-block!important}.ew-btn-loading.layui-btn-sm>.ew-btn-loading-text,.ew-btn-loading.layui-btn-xs>.ew-btn-loading-text{font-size:12px!important}.ew-btn-loading.layui-btn-lg>.ew-btn-loading-text{font-size:16px!important}.ew-btn-loading>.ew-btn-loading-text *{display:inline-block!important}.form-search-expand,.form-search-expand:hover{padding:0!important;color:#2d8cf0!important;border:none!important;box-shadow:none!important;background-color:transparent!important}.form-search-expand .layui-icon{font-size:12px!important;font-weight:600!important}.form-search-show-expand{display:none!important}.layui-badge-green{color:#52c41a;background:#f6ffed;border:1px solid #b7eb8f}.layui-badge-blue{color:#1890ff;background:#e6f7ff;border:1px solid #91d5ff}.layui-badge-red{color:#f5222d;background:#fff1f0;border:1px solid #ffa39e}.layui-badge-yellow{color:#faad14;background:#fffbe6;border:1px solid #ffe58f}.layui-badge-gray{color:#8c8c8c;background:#fafafa;border:1px solid #ccc}.layui-badge{height:20px;line-height:19px;box-sizing:border-box}.layui-badge-list .layui-badge{height:23px;line-height:22px;margin:0 6px 8px 0}.layui-badge-list .layui-badge.layui-bg-gray{border:1px solid #ccc;background-color:#fafafa!important}.layui-card .layui-card-header .layui-badge.pull-right{top:50%;margin-top:-10px}#ew-lock-screen-group{position:fixed;top:0;left:0;right:0;bottom:0;z-index:19891099}.ios-iframe-body{position:absolute;top:0;left:0;right:0;bottom:0}xm-select>.xm-body{margin-left:-2px}xm-select>.xm-body .xm-option{background-color:transparent!important}xm-select>.xm-body .xm-option.hide-icon.selected{background-color:#5fb878!important}xm-select>.xm-body .xm-option:hover{background-color:#f2f2f2!important}.xm-body .xm-tree{min-width:200px}.xm-body .xm-tree .xm-option-content{padding-left:6px}xm-select{border-color:#e6e6e6!important}xm-select:hover{border-color:#d2d2d2!important}xm-select[style="border-color: rgb(229, 77, 66);"]{border-color:#e54d42!important}body .ew-xmselect-tree xm-select .xm-body .xm-option .xm-option-icon{position:absolute;left:30px;top:0;right:0;bottom:0;width:auto;height:auto;border:none!important;z-index:1}body .ew-xmselect-tree xm-select .xm-body .xm-option .xm-option-icon:before{display:none}body .ew-xmselect-tree xm-select .xm-body .xm-option.selected{background-color:#f2f2f2!important}body .ew-xmselect-tree xm-select .xm-body .xm-option.selected .xm-option-content{color:#5fb878!important}.theme-blue .layui-layout-admin .layui-header .layui-logo{color:#fff;box-shadow:none;background-color:transparent}.theme-blue .layui-layout-admin .layui-header{background-color:#3c8dbc}.theme-blue .layui-layout-admin .layui-header a{color:#fff}.theme-blue .layui-layout-admin .layui-header a:hover{color:#fff}.theme-blue .layui-layout-admin .layui-header .layui-nav-child a{color:#595959}.theme-blue .layui-layout-admin .layui-header .layui-nav .layui-nav-more{border-color:#eee transparent transparent}.theme-blue .layui-layout-admin .layui-header .layui-nav .layui-nav-mored{border-color:transparent transparent #eee}.theme-blue .layui-layout-admin .layui-header .layui-nav .layui-this:after,.theme-blue .layui-layout-admin .layui-header .layui-nav-bar{background-color:#fff}.theme-blue .layui-layout-admin .layui-side{background-color:#222d32}.theme-blue .layui-side .layui-nav .layui-nav-item a{color:#b8c7ce}.theme-blue .layui-nav-tree .layui-nav-child dd.layui-this a,.theme-blue .layui-nav-tree .layui-this>a,.theme-blue .layui-nav-tree .layui-this>a:hover{color:#fff;background-color:#3c8dbc}.theme-blue .layui-nav-tree>.layui-nav-item>a:before{background-color:#3c8dbc}.theme-blue .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child:before{background:#222d32!important}.theme-blue .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this:after{background-color:#3c8dbc;top:38px}.theme-blue .layui-body-header-title{border-left-color:#3c8dbc}.theme-blue .layui-layer.layui-layer-admin .layui-layer-title{background-color:#3c8dbc}.theme-blue .layui-layer.layui-layer-admin .layui-layer-btn .layui-layer-btn0{border-color:#3c8dbc;background-color:#3c8dbc}.theme-blue .ball-loader>span,.theme-blue .signal-loader>span{background-color:#3c8dbc}.theme-blue .btn-circle{background:#3c8dbc}.theme-blue .more-theme-item:hover,.theme-blue .more-theme-item.active{border-color:#3c8dbc}.theme-blue .text-primary,.theme-blue .layui-link{color:#3c8dbc!important}.theme-blue .layui-btn{background-color:#3c8dbc}.theme-blue .layui-form-onswitch{border-color:#3c8dbc;background-color:#3c8dbc}.theme-blue .layui-form-radio>i:hover,.theme-blue .layui-form-radioed>i,.theme-blue .layui-form-checked i,.theme-blue .layui-form-checked:hover i{color:#3c8dbc}.theme-blue .layui-form-checked[lay-skin=primary] i,.theme-blue .layui-form-checked span,.theme-blue .layui-form-checked:hover span{border-color:#3c8dbc!important;background-color:#3c8dbc}.theme-blue .layui-form-checked[lay-skin=primary] i:hover,.theme-blue .layui-form-checkbox[lay-skin=primary]:hover i{border-color:#3c8dbc!important}.theme-blue .layui-form-select dl dd.layui-this{background-color:#3c8dbc}.theme-blue .layui-laypage .layui-laypage-curr .layui-laypage-em{background-color:#3c8dbc}.theme-blue .layui-laypage input:focus,.theme-blue .layui-laypage select:focus{border-color:#3c8dbc!important}.theme-blue .layui-laypage a:hover{color:#3c8dbc}.theme-blue .layui-tab-brief>.layui-tab-title .layui-this{color:#3c8dbc}.theme-blue .layui-tab-brief>.layui-tab-more li.layui-this:after,.theme-blue .layui-tab-brief>.layui-tab-title .layui-this:after{border-color:#3c8dbc!important}.theme-blue .layui-tab.layui-tab-vertical>.layui-tab-title>li.layui-this{border-color:#3c8dbc;color:#3c8dbc}.theme-blue .layui-breadcrumb a:hover{color:#3c8dbc!important}.theme-blue .layui-laydate-footer span:hover,.theme-blue .layui-laydate-header i:hover,.theme-blue .layui-laydate-header span:hover{color:#3c8dbc}.theme-blue .layui-laydate .layui-this{background-color:#3c8dbc!important}.theme-blue .layui-laydate-content td.laydate-selected{background-color:rgba(60,141,188,.1)}.theme-blue .laydate-selected:hover{background-color:rgba(60,141,188,.1)!important}.theme-blue .layui-timeline-axis{color:#3c8dbc}.theme-blue .layui-transfer-active .layui-btn{background-color:#3c8dbc!important;border-color:#3c8dbc!important}.theme-blue .layui-progress-bar{background-color:#3c8dbc}.theme-blue .layui-slider-bar{background-color:#3c8dbc!important}.theme-blue .layui-slider-wrap-btn{border-color:#3c8dbc!important}.theme-blue .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon{color:#3c8dbc}.theme-blue .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon.layui-icon-ok,.theme-blue .layui-elem-quote{border-color:#3c8dbc}.theme-blue .layui-tab.layui-steps>.layui-tab-title>li:before,.theme-blue .layui-tab.layui-steps>.layui-tab-title>li.layui-this>.layui-icon.layui-icon-ok{background-color:#3c8dbc}.theme-blue .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li{background-color:#9dc6dd}.theme-blue .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this{background-color:#3c8dbc}.theme-blue .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li:after{border-left-color:#9dc6dd!important}.theme-blue .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this+li:after{border-left-color:#3c8dbc!important}.theme-blue .ew-cascader-dropdown-list-item.active,.theme-blue .ew-cascader-dropdown-list-item.active .ew-icon-right{color:#3c8dbc}.theme-blue div.tagsinput span.tag{background:#3c8dbc}.theme-blue xm-select .xm-body .xm-option .xm-option-icon{border-color:#3c8dbc!important}.theme-blue xm-select .xm-body .xm-option.selected .xm-option-icon,.theme-blue xm-select>.xm-body .xm-toolbar .toolbar-tag:hover,.theme-blue .ew-xmselect-tree xm-select .xm-body .xm-option.selected .xm-option-content{color:#3c8dbc!important}.theme-blue xm-select .xm-label .xm-label-block,.theme-blue xm-select .xm-body .xm-option.hide-icon.selected{background-color:#3c8dbc!important}.theme-blue .city-select a.active{color:#fff!important;background-color:#3c8dbc!important}.theme-blue .city-select a:hover,.theme-blue .city-select a:focus{background-color:rgba(60,141,188,.1);color:#3c8dbc}.theme-blue .city-picker-span>.title>span:hover{background-color:rgba(60,141,188,.1)}.theme-blue .city-select-tab>a.active{color:#3c8dbc}.theme-green .layui-layout-admin .layui-header .layui-logo{color:#fff;box-shadow:none;background-color:transparent}.theme-green .layui-layout-admin .layui-header{background-color:#00a65a}.theme-green .layui-layout-admin .layui-header a{color:#fff}.theme-green .layui-layout-admin .layui-header a:hover{color:#fff}.theme-green .layui-layout-admin .layui-header .layui-nav-child a{color:#595959}.theme-green .layui-layout-admin .layui-header .layui-nav .layui-nav-more{border-color:#eee transparent transparent}.theme-green .layui-layout-admin .layui-header .layui-nav .layui-nav-mored{border-color:transparent transparent #eee}.theme-green .layui-layout-admin .layui-header .layui-nav .layui-this:after,.theme-green .layui-layout-admin .layui-header .layui-nav-bar{background-color:#fff}.theme-green .layui-layout-admin .layui-side{background-color:#222d32}.theme-green .layui-side .layui-nav .layui-nav-item a{color:#b8c7ce}.theme-green .layui-nav-tree .layui-nav-child dd.layui-this a,.theme-green .layui-nav-tree .layui-this>a,.theme-green .layui-nav-tree .layui-this>a:hover{color:#fff;background-color:#00a65a}.theme-green .layui-nav-tree>.layui-nav-item>a:before{background-color:#00a65a}.theme-green .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child:before{background:#222d32!important}.theme-green .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this:after{background-color:#00a65a;top:38px}.theme-green .layui-body-header-title{border-left-color:#00a65a}.theme-green .layui-layer.layui-layer-admin .layui-layer-title{background-color:#00a65a}.theme-green .layui-layer.layui-layer-admin .layui-layer-btn .layui-layer-btn0{border-color:#00a65a;background-color:#00a65a}.theme-green .more-theme-item:hover,.theme-green .more-theme-item.active{border-color:#00a65a}.theme-green .btn-circle{background:#00a65a}.theme-green .ball-loader>span,.theme-green .signal-loader>span{background-color:#00a65a}.theme-green .text-primary,.theme-green .layui-link{color:#00a65a!important}.theme-green .layui-btn{background-color:#00a65a}.theme-green .layui-form-onswitch{border-color:#00a65a;background-color:#00a65a}.theme-green .layui-form-radio>i:hover,.theme-green .layui-form-radioed>i,.theme-green .layui-form-checked i,.theme-green .layui-form-checked:hover i{color:#00a65a}.theme-green .layui-form-checked[lay-skin=primary] i,.theme-green .layui-form-checked span,.theme-green .layui-form-checked:hover span{border-color:#00a65a!important;background-color:#00a65a}.theme-green .layui-form-checked[lay-skin=primary] i:hover,.theme-green .layui-form-checkbox[lay-skin=primary]:hover i{border-color:#00a65a!important}.theme-green .layui-form-select dl dd.layui-this{background-color:#00a65a}.theme-green .layui-laypage .layui-laypage-curr .layui-laypage-em{background-color:#00a65a}.theme-green .layui-laypage input:focus,.theme-green .layui-laypage select:focus{border-color:#00a65a!important}.theme-green .layui-laypage a:hover{color:#00a65a}.theme-green .layui-tab-brief>.layui-tab-title .layui-this{color:#00a65a}.theme-green .layui-tab-brief>.layui-tab-more li.layui-this:after,.theme-green .layui-tab-brief>.layui-tab-title .layui-this:after{border-color:#00a65a!important}.theme-green .layui-tab.layui-tab-vertical>.layui-tab-title>li.layui-this{border-color:#00a65a;color:#00a65a}.theme-green .layui-breadcrumb a:hover{color:#00a65a!important}.theme-green .layui-laydate-footer span:hover,.theme-green .layui-laydate-header i:hover,.theme-green .layui-laydate-header span:hover{color:#00a65a}.theme-green .layui-laydate .layui-this{background-color:#00a65a!important}.theme-green .layui-laydate-content td.laydate-selected{background-color:rgba(0,166,90,.1)}.theme-green .laydate-selected:hover{background-color:rgba(0,166,90,.1)!important}.theme-green .layui-timeline-axis{color:#00a65a}.theme-green .layui-transfer-active .layui-btn{background-color:#00a65a!important;border-color:#00a65a!important}.theme-green .layui-progress-bar{background-color:#00a65a}.theme-green .layui-slider-bar{background-color:#00a65a!important}.theme-green .layui-slider-wrap-btn{border-color:#00a65a!important}.theme-green .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon{color:#00a65a}.theme-green .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon.layui-icon-ok,.theme-green .layui-elem-quote{border-color:#00a65a}.theme-green .layui-tab.layui-steps>.layui-tab-title>li:before,.theme-green .layui-tab.layui-steps>.layui-tab-title>li.layui-this>.layui-icon.layui-icon-ok{background-color:#00a65a}.theme-green .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li{background-color:#7fd2ac}.theme-green .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this{background-color:#00a65a}.theme-green .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li:after{border-left-color:#7fd2ac!important}.theme-green .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this+li:after{border-left-color:#00a65a!important}.theme-green .ew-cascader-dropdown-list-item.active,.theme-green .ew-cascader-dropdown-list-item.active .ew-icon-right{color:#00a65a}.theme-green div.tagsinput span.tag{background:#00a65a}.theme-green xm-select .xm-body .xm-option .xm-option-icon{border-color:#00a65a!important}.theme-green xm-select .xm-body .xm-option.selected .xm-option-icon,.theme-green xm-select>.xm-body .xm-toolbar .toolbar-tag:hover,.theme-green .ew-xmselect-tree xm-select .xm-body .xm-option.selected .xm-option-content{color:#00a65a!important}.theme-green xm-select .xm-label .xm-label-block,.theme-green xm-select .xm-body .xm-option.hide-icon.selected{background-color:#00a65a!important}.theme-green .city-select a.active{color:#fff!important;background-color:#00a65a!important}.theme-green .city-select a:hover,.theme-green .city-select a:focus{background-color:rgba(0,166,90,.1);color:#00a65a}.theme-green .city-picker-span>.title>span:hover{background-color:rgba(0,166,90,.1)}.theme-green .city-select-tab>a.active{color:#00a65a}.theme-purple .layui-layout-admin .layui-header .layui-logo{color:#fff;box-shadow:none;background-color:transparent}.theme-purple .layui-layout-admin .layui-header{background-color:#722ed1}.theme-purple .layui-layout-admin .layui-header a{color:#fff}.theme-purple .layui-layout-admin .layui-header a:hover{color:#fff}.theme-purple .layui-layout-admin .layui-header .layui-nav-child a{color:#595959}.theme-purple .layui-layout-admin .layui-header .layui-nav .layui-nav-more{border-color:#eee transparent transparent}.theme-purple .layui-layout-admin .layui-header .layui-nav .layui-nav-mored{border-color:transparent transparent #eee}.theme-purple .layui-layout-admin .layui-header .layui-nav .layui-this:after,.theme-purple .layui-layout-admin .layui-header .layui-nav-bar{background-color:#fff}.theme-purple .layui-layout-admin .layui-side{background-color:#222d32}.theme-purple .layui-side .layui-nav .layui-nav-item a{color:#b8c7ce}.theme-purple .layui-nav-tree .layui-nav-child dd.layui-this a,.theme-purple .layui-nav-tree .layui-this>a,.theme-purple .layui-nav-tree .layui-this>a:hover{color:#fff;background-color:#722ed1}.theme-purple .layui-nav-tree>.layui-nav-item>a:before{background-color:#722ed1}.theme-purple .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child:before{background:#222d32!important}.theme-purple .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this:after{background-color:#722ed1;top:38px}.theme-purple .layui-body-header-title{border-left-color:#722ed1}.theme-purple .layui-layer.layui-layer-admin .layui-layer-title{background-color:#722ed1}.theme-purple .layui-layer.layui-layer-admin .layui-layer-btn .layui-layer-btn0{border-color:#722ed1;background-color:#722ed1}.theme-purple .more-theme-item:hover,.theme-purple .more-theme-item.active{border-color:#722ed1}.theme-purple .btn-circle{background:#722ed1}.theme-purple .ball-loader>span,.theme-purple .signal-loader>span{background-color:#722ed1}.theme-purple .text-primary,.theme-purple .layui-link{color:#722ed1!important}.theme-purple .layui-btn{background-color:#722ed1}.theme-purple .layui-form-onswitch{border-color:#722ed1;background-color:#722ed1}.theme-purple .layui-form-radio>i:hover,.theme-purple .layui-form-radioed>i,.theme-purple .layui-form-checked i,.theme-purple .layui-form-checked:hover i{color:#722ed1}.theme-purple .layui-form-checked[lay-skin=primary] i,.theme-purple .layui-form-checked span,.theme-purple .layui-form-checked:hover span{border-color:#722ed1!important;background-color:#722ed1}.theme-purple .layui-form-checked[lay-skin=primary] i:hover,.theme-purple .layui-form-checkbox[lay-skin=primary]:hover i{border-color:#722ed1!important}.theme-purple .layui-form-select dl dd.layui-this{background-color:#722ed1}.theme-purple .layui-laypage .layui-laypage-curr .layui-laypage-em{background-color:#722ed1}.theme-purple .layui-laypage input:focus,.theme-purple .layui-laypage select:focus{border-color:#722ed1!important}.theme-purple .layui-laypage a:hover{color:#722ed1}.theme-purple .layui-tab-brief>.layui-tab-title .layui-this{color:#722ed1}.theme-purple .layui-tab-brief>.layui-tab-more li.layui-this:after,.theme-purple .layui-tab-brief>.layui-tab-title .layui-this:after{border-color:#722ed1!important}.theme-purple .layui-tab.layui-tab-vertical>.layui-tab-title>li.layui-this{border-color:#722ed1;color:#722ed1}.theme-purple .layui-breadcrumb a:hover{color:#722ed1!important}.theme-purple .layui-laydate-footer span:hover,.theme-purple .layui-laydate-header i:hover,.theme-purple .layui-laydate-header span:hover{color:#722ed1}.theme-purple .layui-laydate .layui-this{background-color:#722ed1!important}.theme-purple .layui-laydate-content td.laydate-selected{background-color:rgba(114,46,209,.1)}.theme-purple .laydate-selected:hover{background-color:rgba(114,46,209,.1)!important}.theme-purple .layui-timeline-axis{color:#722ed1}.theme-purple .layui-transfer-active .layui-btn{background-color:#722ed1!important;border-color:#722ed1!important}.theme-purple .layui-progress-bar{background-color:#722ed1}.theme-purple .layui-slider-bar{background-color:#722ed1!important}.theme-purple .layui-slider-wrap-btn{border-color:#722ed1!important}.theme-purple .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon{color:#722ed1}.theme-purple .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon.layui-icon-ok,.theme-purple .layui-elem-quote{border-color:#722ed1}.theme-purple .layui-tab.layui-steps>.layui-tab-title>li:before,.theme-purple .layui-tab.layui-steps>.layui-tab-title>li.layui-this>.layui-icon.layui-icon-ok{background-color:#722ed1}.theme-purple .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li{background-color:#b896e8}.theme-purple .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this{background-color:#722ed1}.theme-purple .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li:after{border-left-color:#b896e8!important}.theme-purple .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this+li:after{border-left-color:#722ed1!important}.theme-purple .ew-cascader-dropdown-list-item.active,.theme-purple .ew-cascader-dropdown-list-item.active .ew-icon-right{color:#722ed1}.theme-purple div.tagsinput span.tag{background:#722ed1}.theme-purple xm-select .xm-body .xm-option .xm-option-icon{border-color:#722ed1!important}.theme-purple xm-select .xm-body .xm-option.selected .xm-option-icon,.theme-purple xm-select>.xm-body .xm-toolbar .toolbar-tag:hover,.theme-purple .ew-xmselect-tree xm-select .xm-body .xm-option.selected .xm-option-content{color:#722ed1!important}.theme-purple xm-select .xm-label .xm-label-block,.theme-purple xm-select .xm-body .xm-option.hide-icon.selected{background-color:#722ed1!important}.theme-purple .city-select a.active{color:#fff!important;background-color:#722ed1!important}.theme-purple .city-select a:hover,.theme-purple .city-select a:focus{background-color:rgba(114,46,209,.1);color:#722ed1}.theme-purple .city-picker-span>.title>span:hover{background-color:rgba(114,46,209,.1)}.theme-purple .city-select-tab>a.active{color:#722ed1}.theme-red .layui-layout-admin .layui-header .layui-logo{color:#fff;box-shadow:none;background-color:transparent}.theme-red .layui-layout-admin .layui-header{background-color:#dd4b39}.theme-red .layui-layout-admin .layui-header a{color:#fff}.theme-red .layui-layout-admin .layui-header a:hover{color:#fff}.theme-red .layui-layout-admin .layui-header .layui-nav-child a{color:#595959}.theme-red .layui-layout-admin .layui-header .layui-nav .layui-nav-more{border-color:#eee transparent transparent}.theme-red .layui-layout-admin .layui-header .layui-nav .layui-nav-mored{border-color:transparent transparent #eee}.theme-red .layui-layout-admin .layui-header .layui-nav .layui-this:after,.theme-red .layui-layout-admin .layui-header .layui-nav-bar{background-color:#fff}.theme-red .layui-layout-admin .layui-side{background-color:#28333e}.theme-red .layui-nav-tree .layui-nav-child dd.layui-this a,.theme-red .layui-nav-tree .layui-this>a,.theme-red .layui-nav-tree .layui-this>a:hover{background-color:#dd4b39}.theme-red .layui-nav-tree>.layui-nav-item>a:before{background-color:#dd4b39}.theme-red .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child:before{background:#28333e!important}.theme-red .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this:after{background-color:#dd4b39;top:38px}.theme-red .layui-body-header-title{border-left-color:#dd4b39}.theme-red .layui-layer.layui-layer-admin .layui-layer-title{background-color:#dd4b39}.theme-red .layui-layer.layui-layer-admin .layui-layer-btn .layui-layer-btn0{border-color:#dd4b39;background-color:#dd4b39}.theme-red .more-theme-item:hover,.theme-red .more-theme-item.active{border-color:#dd4b39}.theme-red .btn-circle{background:#dd4b39}.theme-red .ball-loader>span,.theme-red .signal-loader>span{background-color:#dd4b39}.theme-red .text-primary,.theme-red .layui-link{color:#dd4b39!important}.theme-red .layui-btn{background-color:#dd4b39}.theme-red .layui-form-onswitch{border-color:#dd4b39;background-color:#dd4b39}.theme-red .layui-form-radio>i:hover,.theme-red .layui-form-radioed>i,.theme-red .layui-form-checked i,.theme-red .layui-form-checked:hover i{color:#dd4b39}.theme-red .layui-form-checked[lay-skin=primary] i,.theme-red .layui-form-checked span,.theme-red .layui-form-checked:hover span{border-color:#dd4b39!important;background-color:#dd4b39}.theme-red .layui-form-checked[lay-skin=primary] i:hover,.theme-red .layui-form-checkbox[lay-skin=primary]:hover i{border-color:#dd4b39!important}.theme-red .layui-form-select dl dd.layui-this{background-color:#dd4b39}.theme-red .layui-laypage .layui-laypage-curr .layui-laypage-em{background-color:#dd4b39}.theme-red .layui-laypage input:focus,.theme-red .layui-laypage select:focus{border-color:#dd4b39!important}.theme-red .layui-laypage a:hover{color:#dd4b39}.theme-red .layui-tab-brief>.layui-tab-title .layui-this{color:#dd4b39}.theme-red .layui-tab-brief>.layui-tab-more li.layui-this:after,.theme-red .layui-tab-brief>.layui-tab-title .layui-this:after{border-color:#dd4b39!important}.theme-red .layui-tab.layui-tab-vertical>.layui-tab-title>li.layui-this{border-color:#dd4b39;color:#dd4b39}.theme-red .layui-breadcrumb a:hover{color:#dd4b39!important}.theme-red .layui-laydate-footer span:hover,.theme-red .layui-laydate-header i:hover,.theme-red .layui-laydate-header span:hover{color:#dd4b39}.theme-red .layui-laydate .layui-this{background-color:#dd4b39!important}.theme-red .layui-laydate-content td.laydate-selected{background-color:rgba(221,75,57,.1)}.theme-red .laydate-selected:hover{background-color:rgba(221,75,57,.1)!important}.theme-red .layui-timeline-axis{color:#dd4b39}.theme-red .layui-transfer-active .layui-btn{background-color:#dd4b39!important;border-color:#dd4b39!important}.theme-red .layui-progress-bar{background-color:#dd4b39}.theme-red .layui-slider-bar{background-color:#dd4b39!important}.theme-red .layui-slider-wrap-btn{border-color:#dd4b39!important}.theme-red .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon{color:#dd4b39}.theme-red .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon.layui-icon-ok,.theme-red .layui-elem-quote{border-color:#dd4b39}.theme-red .layui-tab.layui-steps>.layui-tab-title>li:before,.theme-red .layui-tab.layui-steps>.layui-tab-title>li.layui-this>.layui-icon.layui-icon-ok{background-color:#dd4b39}.theme-red .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li{background-color:#eea39a}.theme-red .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this{background-color:#dd4b39}.theme-red .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li:after{border-left-color:#eea39a!important}.theme-red .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this+li:after{border-left-color:#dd4b39!important}.theme-red .ew-cascader-dropdown-list-item.active,.theme-red .ew-cascader-dropdown-list-item.active .ew-icon-right{color:#dd4b39}.theme-red div.tagsinput span.tag{background:#dd4b39}.theme-red xm-select .xm-body .xm-option .xm-option-icon{border-color:#dd4b39!important}.theme-red xm-select .xm-body .xm-option.selected .xm-option-icon,.theme-red xm-select>.xm-body .xm-toolbar .toolbar-tag:hover,.theme-red .ew-xmselect-tree xm-select .xm-body .xm-option.selected .xm-option-content{color:#dd4b39!important}.theme-red xm-select .xm-label .xm-label-block,.theme-red xm-select .xm-body .xm-option.hide-icon.selected{background-color:#dd4b39!important}.theme-red .city-select a.active{color:#fff!important;background-color:#dd4b39!important}.theme-red .city-select a:hover,.theme-red .city-select a:focus{background-color:rgba(221,75,57,.1);color:#dd4b39}.theme-red .city-picker-span>.title>span:hover{background-color:rgba(221,75,57,.1)}.theme-red .city-select-tab>a.active{color:#dd4b39}.theme-cyan .layui-layout-admin .layui-header .layui-logo{background-color:#001529}.theme-cyan .layui-layout-admin .layui-header .layui-nav .layui-this:after,.theme-cyan .layui-layout-admin .layui-header .layui-nav-bar{background-color:#001529}.theme-cyan .layui-layout-admin .layui-side{background-color:#001529}.theme-cyan .layui-nav-tree .layui-nav-child dd.layui-this a,.theme-cyan .layui-nav-tree .layui-this>a,.theme-cyan .layui-nav-tree .layui-this>a:hover{background-color:#1890ff}.theme-cyan .layui-nav-tree>.layui-nav-item>a:before{background-color:#1890ff}.theme-cyan .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child:before{background:#001529!important}.theme-cyan .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this:after{background-color:#001529}.theme-cyan .layui-body-header-title{border-left-color:#1890ff}.theme-cyan .layui-layer.layui-layer-admin{border-radius:4px}.theme-cyan .layui-layer.layui-layer-admin .layui-layer-title{color:#333;font-size:16px;padding-left:23px;background-color:#fff;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:1px solid #f1f1f1}.theme-cyan .layui-layer.layui-layer-admin .layui-layer-setwin a{color:#8c8c8c;font-weight:600}.theme-cyan .layui-layer.layui-layer-admin .layui-layer-setwin .layui-layer-min cite{background-color:#8c8c8c}.theme-cyan .layui-layer.layui-layer-admin .layui-layer-btn a{height:32px;line-height:32px;border-radius:4px;box-shadow:0 1px 0 rgba(0,0,0,.03)}.theme-cyan .layui-layer.layui-layer-admin .layui-layer-btn .layui-layer-btn0{border-color:#1890ff;background-color:#1890ff}.theme-cyan .more-theme-item:hover,.theme-cyan .more-theme-item.active{border-color:#1890ff}.theme-cyan .btn-circle{background:#1890ff}.theme-cyan .ball-loader>span,.theme-cyan .signal-loader>span{background-color:#1890ff}.theme-cyan .text-primary,.theme-cyan .layui-link{color:#1890ff!important}.theme-cyan .layui-btn{height:36px;line-height:36px;border-radius:4px;background-color:#1890ff;box-shadow:0 1px 0 rgba(0,0,0,.03)}.theme-cyan .layui-btn-lg{height:42px;line-height:42px}.theme-cyan .layui-btn-sm{height:28px;line-height:28px}.theme-cyan .layui-btn-xs{height:22px;line-height:22px}.theme-cyan .layui-input,.theme-cyan .layui-select,.theme-cyan .layui-textarea,.theme-cyan xm-select{height:36px;border-radius:4px}.theme-cyan .layui-input:focus,.theme-cyan .layui-textarea:focus,.theme-cyan xm-select:hover{border-color:#40a9ff!important}.theme-cyan .layui-form-label,.theme-cyan .layui-form-mid{padding-top:8px;padding-bottom:8px}.theme-cyan .layui-input-block{min-height:36px}.theme-cyan .layui-form-radio{margin-top:4px}.theme-cyan .layui-form-onswitch{border-color:#1890ff;background-color:#1890ff}.theme-cyan .layui-form-radio>i:hover,.theme-cyan .layui-form-radioed>i,.theme-cyan .layui-form-checked i,.theme-cyan .layui-form-checked:hover i{color:#1890ff}.theme-cyan .layui-form-checked[lay-skin=primary] i,.theme-cyan .layui-form-checked span,.theme-cyan .layui-form-checked:hover span{border-color:#1890ff!important;background-color:#1890ff}.theme-cyan .layui-form-checked[lay-skin=primary] i:hover,.theme-cyan .layui-form-checkbox[lay-skin=primary]:hover i{border-color:#1890ff!important}.theme-cyan .layui-form-select dl dd.layui-this{background-color:#1890ff}.theme-cyan .layui-laypage .layui-laypage-curr .layui-laypage-em{background-color:#1890ff}.theme-cyan .layui-laypage input:focus,.theme-cyan .layui-laypage select:focus{border-color:#1890ff!important}.theme-cyan .layui-laypage a:hover{color:#1890ff}.theme-cyan .layui-tab-brief>.layui-tab-title .layui-this{color:#1890ff}.theme-cyan .layui-tab-brief>.layui-tab-more li.layui-this:after,.theme-cyan .layui-tab-brief>.layui-tab-title .layui-this:after{border-color:#1890ff!important}.theme-cyan .layui-tab.layui-tab-vertical>.layui-tab-title>li.layui-this{border-color:#2d8cf0;color:#2d8cf0}.theme-cyan .layui-breadcrumb a:hover{color:#1890ff!important}.theme-cyan .layui-laydate-footer span:hover,.theme-cyan .layui-laydate-header i:hover,.theme-cyan .layui-laydate-header span:hover{color:#1890ff}.theme-cyan .layui-laydate .layui-this{background-color:#1890ff!important}.theme-cyan .layui-laydate-content td.laydate-selected{background-color:rgba(24,144,255,.1)}.theme-cyan .laydate-selected:hover{background-color:rgba(24,144,255,.1)!important}.theme-cyan .layui-timeline-axis{color:#1890ff}.theme-cyan .layui-transfer-active .layui-btn{background-color:#1890ff!important;border-color:#1890ff!important}.theme-cyan .layui-progress-bar{background-color:#1890ff}.theme-cyan .layui-slider-bar{background-color:#1890ff!important}.theme-cyan .layui-slider-wrap-btn{border-color:#1890ff!important}.theme-cyan .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon{color:#1890ff}.theme-cyan .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon.layui-icon-ok,.theme-cyan .layui-elem-quote{border-color:#1890ff}.theme-cyan .layui-tab.layui-steps>.layui-tab-title>li:before,.theme-cyan .layui-tab.layui-steps>.layui-tab-title>li.layui-this>.layui-icon.layui-icon-ok{background-color:#1890ff}.theme-cyan .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li{background-color:#89c6ff}.theme-cyan .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this{background-color:#1890ff}.theme-cyan .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li:after{border-left-color:#89c6ff!important}.theme-cyan .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this+li:after{border-left-color:#1890ff!important}.theme-cyan .ew-cascader-dropdown-list-item.active,.theme-cyan .ew-cascader-dropdown-list-item.active .ew-icon-right{color:#1890ff}.theme-cyan div.tagsinput span.tag{background:#1890ff}.theme-cyan xm-select .xm-body .xm-option .xm-option-icon{border-color:#1890ff!important}.theme-cyan xm-select .xm-body .xm-option.selected .xm-option-icon,.theme-cyan xm-select>.xm-body .xm-toolbar .toolbar-tag:hover,.theme-cyan .ew-xmselect-tree xm-select .xm-body .xm-option.selected .xm-option-content{color:#1890ff!important}.theme-cyan xm-select .xm-label .xm-label-block,.theme-cyan xm-select .xm-body .xm-option.hide-icon.selected{background-color:#1890ff!important}.theme-cyan .city-select a.active{color:#fff!important;background-color:#1890ff!important}.theme-cyan .city-select a:hover,.theme-cyan .city-select a:focus{background-color:#f0faff;color:#1890ff}.theme-cyan .city-picker-span>.title>span:hover{background-color:#f0faff}.theme-cyan .city-select-tab>a.active{color:#1890ff}.theme-white .layui-layout-admin .layui-header .layui-logo{color:#262626;background-color:transparent;box-shadow:2px 8px 8px 0 rgba(29,35,41,.05)}.theme-white .layui-layout-admin .layui-header{box-shadow:0 1px 4px rgba(0,21,41,.08)}.theme-white .layui-layout-admin .layui-header .layui-nav .layui-this:after,.theme-white .layui-layout-admin .layui-header .layui-nav-bar{background-color:#2d8cf0}.theme-white .layui-layout-admin .layui-side{background-color:#fff;box-shadow:2px 8px 8px 0 rgba(29,35,41,.05)}.theme-white .layui-side .layui-nav .layui-nav-item a{color:#595959}.theme-white .layui-side .layui-nav .layui-nav-item a:hover{color:#2d8cf0}.theme-white .layui-side .layui-nav-itemed>a,.theme-white .layui-side .layui-nav-tree .layui-nav-title a,.theme-white .layui-side .layui-nav-tree .layui-nav-title a:hover{color:#595959!important}.theme-white .layui-side .layui-nav-itemed>a:hover{color:#2d8cf0!important}.theme-white .layui-side .layui-nav-tree .layui-nav-child dd.layui-this a,.theme-white .layui-side .layui-nav-tree .layui-this>a,.theme-white .layui-side .layui-nav-tree .layui-this>a:hover{color:#2d8cf0;background:#f0faff;border-right:2px solid #2d8cf0}.theme-white .layui-side .layui-nav-tree .layui-nav-item .layui-nav-child{background-color:transparent!important}.theme-white .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child:before{background:#fff!important}@media screen and (min-width:769px){.theme-white .layui-layout-admin.admin-nav-mini .layui-side .layui-nav li.layui-nav-itemed>a{background:#f0faff;color:#2d8cf0!important}}.theme-white .layui-nav-tree>.layui-nav-item>a:before{display:none}.theme-white .layui-side .layui-nav .layui-nav-more{border-color:rgba(89,89,89,.7) transparent transparent}.theme-white .layui-side .layui-nav .layui-nav-mored,.theme-white .layui-side .layui-nav-itemed>a .layui-nav-more{border-color:transparent transparent rgba(89,89,89,.7)}.theme-white .layui-side .layui-nav-tree.arrow3 .layui-nav-itemed>a>.layui-nav-more:before{background-color:rgba(89,89,89,.7)}@media screen and (min-width:769px){.theme-white .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child>dd>a .layui-nav-more{border-color:transparent transparent transparent rgba(89,89,89,.7)}}.theme-white .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title{top:8px;right:8px;height:32px;line-height:32px;box-sizing:border-box;background-color:transparent;box-shadow:-4px 4px 0 #f5f7f9;padding-right:70px}.theme-white .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li{border:0;margin-right:6px;border-radius:4px;background-color:#fff;line-height:32px;height:32px}.theme-white .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this{color:#2d8cf0;background-color:#fff}.theme-white .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li:hover{background-color:#fff}.theme-white .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this:after{display:none}.theme-white .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li .layui-tab-close,.theme-white .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li .layui-tab-close:hover{top:8px;color:#8c8c8c;background-color:transparent}.theme-white .layui-layout-admin .layui-body .admin-tabs-control,.theme-white .layui-layout-admin .layui-body .admin-tabs-control:hover{top:8px;height:32px;line-height:32px;background-color:#f5f7f9;border:0}.theme-white .layui-layout-admin .layui-body .admin-tabs-control.layui-icon-down{border-radius:4px;background-color:#fff;width:32px;right:8px}.theme-white .admin-tabs-control>.layui-nav .layui-nav-item{line-height:32px}.theme-white .admin-tabs-control>.layui-nav .layui-nav-item>a{height:32px;width:32px;padding:0}.theme-white .admin-tabs-control>.layui-nav .layui-nav-child{top:36px;border:0;border-radius:4px;box-shadow:0 1px 6px rgba(0,0,0,.2)}.theme-white .layui-layout-admin .layui-body .admin-tabs-control.layui-icon-prev:before{content:"\e603"}.theme-white .layui-layout-admin .layui-body .admin-tabs-control.layui-icon-next:before{content:"\e602"}.theme-white .layui-body-header-title{border-left-color:#2d8cf0}.theme-white .layui-body-header{box-shadow:0 1px 4px rgba(0,21,41,.08)}.theme-white .layui-layer.layui-layer-admin{border-radius:4px}.theme-white .layui-layer.layui-layer-admin .layui-layer-title{color:#262626;font-size:16px;padding-left:23px;background-color:#fff;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:1px solid #f1f1f1}.theme-white .layui-layer.layui-layer-admin .layui-layer-setwin a{color:#8c8c8c;font-weight:600}.theme-white .layui-layer.layui-layer-admin .layui-layer-setwin .layui-layer-min cite{background-color:#8c8c8c}.theme-white .layui-layer.layui-layer-admin .layui-layer-btn a{height:32px;line-height:32px;border-radius:4px;box-shadow:0 1px 0 rgba(0,0,0,.03)}.theme-white .layui-layer.layui-layer-admin .layui-layer-btn .layui-layer-btn0{border-color:#2d8cf0;background-color:#2d8cf0}.theme-white .more-theme-item:hover,.theme-white .more-theme-item.active{border-color:#2d8cf0}.theme-white .btn-circle{background:#2d8cf0}.theme-white .ball-loader>span,.theme-white .signal-loader>span{background-color:#2d8cf0}.theme-white .text-primary,.theme-white .layui-link{color:#2d8cf0!important}.theme-white .layui-card{border-radius:4px;box-shadow:none}.theme-white .layui-btn{height:36px;line-height:36px;border-radius:4px;background-color:#2d8cf0;box-shadow:0 1px 0 rgba(0,0,0,.03)}.theme-white .layui-btn-lg{height:42px;line-height:42px}.theme-white .layui-btn-sm{height:28px;line-height:28px}.theme-white .layui-btn-xs{height:22px;line-height:22px}.theme-white .layui-input,.theme-white .layui-select,.theme-white .layui-textarea,.theme-white xm-select{height:36px;border-radius:4px}.theme-white .layui-input:focus,.theme-white .layui-textarea:focus,.theme-white xm-select:hover{border-color:#2d8cf0!important}.theme-white .layui-form-label,.theme-white .layui-form-mid{padding-top:8px;padding-bottom:8px}.theme-white .layui-input-block{min-height:36px}.theme-white .layui-form-radio{margin-top:4px}.theme-white .layui-form-onswitch{border-color:#2d8cf0;background-color:#2d8cf0}.theme-white .layui-form-radio>i:hover,.theme-white .layui-form-radioed>i,.theme-white .layui-form-checked i,.theme-white .layui-form-checked:hover i{color:#2d8cf0}.theme-white .layui-form-checked[lay-skin=primary] i,.theme-white .layui-form-checked span,.theme-white .layui-form-checked:hover span{border-color:#2d8cf0!important;background-color:#2d8cf0}.theme-white .layui-form-checked[lay-skin=primary] i:hover,.theme-white .layui-form-checkbox[lay-skin=primary]:hover i{border-color:#2d8cf0!important}.theme-white .layui-form-select dl dd.layui-this{background-color:#2d8cf0}.theme-white .layui-laypage .layui-laypage-curr .layui-laypage-em{background-color:#2d8cf0}.theme-white .layui-laypage input:focus,.theme-white .layui-laypage select:focus{border-color:#2d8cf0!important}.theme-white .layui-laypage a:hover{color:#2d8cf0}.theme-white .layui-tab-brief>.layui-tab-title .layui-this{color:#2d8cf0}.theme-white .layui-tab-brief>.layui-tab-more li.layui-this:after,.theme-white .layui-tab-brief>.layui-tab-title .layui-this:after{border-color:#2d8cf0!important}.theme-white .layui-tab.layui-tab-vertical>.layui-tab-title>li.layui-this{border-color:#2d8cf0;color:#2d8cf0}.theme-white .layui-breadcrumb a:hover{color:#2d8cf0!important}.theme-white .layui-laydate-footer span:hover,.theme-white .layui-laydate-header i:hover,.theme-white .layui-laydate-header span:hover{color:#2d8cf0}.theme-white .layui-laydate .layui-this{background-color:#2d8cf0!important}.theme-white .layui-laydate-content td.laydate-selected{background-color:rgba(45,140,240,.1)}.theme-white .laydate-selected:hover{background-color:rgba(45,140,240,.1)!important}.theme-white .layui-timeline-axis{color:#2d8cf0}.theme-white .layui-transfer-active .layui-btn{background-color:#2d8cf0!important;border-color:#2d8cf0!important}.theme-white .layui-progress-bar{background-color:#2d8cf0}.theme-white .layui-slider-bar{background-color:#2d8cf0!important}.theme-white .layui-slider-wrap-btn{border-color:#2d8cf0!important}.theme-white .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon{color:#2d8cf0}.theme-white .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon.layui-icon-ok,.theme-white .layui-elem-quote{border-color:#2d8cf0}.theme-white .layui-tab.layui-steps>.layui-tab-title>li:before,.theme-white .layui-tab.layui-steps>.layui-tab-title>li.layui-this>.layui-icon.layui-icon-ok{background-color:#2d8cf0}.theme-white .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li{background-color:#95c5f7}.theme-white .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this{background-color:#2d8cf0}.theme-white .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li:after{border-left-color:#95c5f7!important}.theme-white .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this+li:after{border-left-color:#2d8cf0!important}.theme-white .ew-cascader-dropdown-list-item.active,.theme-white .ew-cascader-dropdown-list-item.active .ew-icon-right{color:#2d8cf0}.theme-white div.tagsinput span.tag{background:#2d8cf0}.theme-white xm-select .xm-body .xm-option .xm-option-icon{border-color:#2d8cf0!important}.theme-white xm-select .xm-body .xm-option.selected .xm-option-icon,.theme-white xm-select>.xm-body .xm-toolbar .toolbar-tag:hover,.theme-white .ew-xmselect-tree xm-select .xm-body .xm-option.selected .xm-option-content{color:#2d8cf0!important}.theme-white xm-select .xm-label .xm-label-block,.theme-white xm-select .xm-body .xm-option.hide-icon.selected{background-color:#2d8cf0!important}.theme-white .city-select a.active{color:#fff!important;background-color:#2d8cf0!important}.theme-white .city-select a:hover,.theme-white .city-select a:focus{background-color:#f0faff;color:#2d8cf0}.theme-white .city-picker-span>.title>span:hover{background-color:#f0faff}.theme-white .city-select-tab>a.active{color:#2d8cf0}.theme-pink .layui-layout-admin .layui-header .layui-logo{color:#262626;background-color:transparent;box-shadow:2px 8px 8px 0 rgba(29,35,41,.05)}.theme-pink .layui-layout-admin .layui-header{box-shadow:0 1px 4px rgba(0,21,41,.08)}.theme-pink .layui-layout-admin .layui-header .layui-nav .layui-this:after,.theme-pink .layui-layout-admin .layui-header .layui-nav-bar{background-color:#fb7299}.theme-pink .layui-layout-admin .layui-side{background-color:#fff;box-shadow:2px 8px 8px 0 rgba(29,35,41,.05)}.theme-pink .layui-side .layui-nav .layui-nav-item a{color:#595959}.theme-pink .layui-side .layui-nav .layui-nav-item a:hover{color:#fb7299}.theme-pink .layui-side .layui-nav-itemed>a,.theme-pink .layui-side .layui-nav-tree .layui-nav-title a,.theme-pink .layui-side .layui-nav-tree .layui-nav-title a:hover{color:#595959!important}.theme-pink .layui-side .layui-nav-itemed>a:hover{color:#fb7299!important}.theme-pink .layui-side .layui-nav-tree .layui-nav-child dd.layui-this a,.theme-pink .layui-side .layui-nav-tree .layui-this>a,.theme-pink .layui-side .layui-nav-tree .layui-this>a:hover{color:#fb7299;background:#fff7f9;border-right:2px solid #fb7299}.theme-pink .layui-side .layui-nav-tree .layui-nav-item .layui-nav-child{background-color:transparent!important}.theme-pink .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child:before{background:#fff!important}@media screen and (min-width:769px){.theme-pink .layui-layout-admin.admin-nav-mini .layui-side .layui-nav li.layui-nav-itemed>a{background:#fff1f5;color:#fb7299!important}}.theme-pink .layui-nav-tree>.layui-nav-item>a:before{display:none}.theme-pink .layui-side .layui-nav .layui-nav-more{border-color:rgba(89,89,89,.7) transparent transparent}.theme-pink .layui-side .layui-nav .layui-nav-mored,.theme-pink .layui-side .layui-nav-itemed>a .layui-nav-more{border-color:transparent transparent rgba(89,89,89,.7)}.theme-pink .layui-side .layui-nav-tree.arrow3 .layui-nav-itemed>a>.layui-nav-more:before{background-color:rgba(89,89,89,.7)}@media screen and (min-width:769px){.theme-pink .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child>dd>a .layui-nav-more{border-color:transparent transparent transparent rgba(89,89,89,.7)}}.theme-pink .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title{top:8px;right:8px;height:32px;line-height:32px;box-sizing:border-box;background-color:transparent;box-shadow:-4px 4px 0 #f5f7f9;padding-right:70px}.theme-pink .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li{border:0;margin-right:6px;border-radius:4px;background-color:#fff;line-height:32px;height:32px}.theme-pink .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this{color:#fb7299;background-color:#fff}.theme-pink .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li:hover{background-color:#fff}.theme-pink .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this:after{display:none}.theme-pink .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li .layui-tab-close,.theme-pink .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li .layui-tab-close:hover{top:8px;color:#8c8c8c;background-color:transparent}.theme-pink .layui-layout-admin .layui-body .admin-tabs-control,.theme-pink .layui-layout-admin .layui-body .admin-tabs-control:hover{top:8px;height:32px;line-height:32px;background-color:#f5f7f9;border:0}.theme-pink .layui-layout-admin .layui-body .admin-tabs-control.layui-icon-down{border-radius:4px;background-color:#fff;width:32px;right:8px}.theme-pink .admin-tabs-control>.layui-nav .layui-nav-item{line-height:32px}.theme-pink .admin-tabs-control>.layui-nav .layui-nav-item>a{height:32px;width:32px;padding:0}.theme-pink .admin-tabs-control>.layui-nav .layui-nav-child{top:36px;border:0;border-radius:4px;box-shadow:0 1px 6px rgba(0,0,0,.2)}.theme-pink .layui-layout-admin .layui-body .admin-tabs-control.layui-icon-prev:before{content:"\e603"}.theme-pink .layui-layout-admin .layui-body .admin-tabs-control.layui-icon-next:before{content:"\e602"}.theme-pink .layui-body-header-title{border-left-color:#fb7299}.theme-pink .layui-body-header{box-shadow:0 1px 4px rgba(0,21,41,.08)}.theme-pink .layui-layer.layui-layer-admin{border-radius:4px}.theme-pink .layui-layer.layui-layer-admin .layui-layer-title{color:#262626;font-size:16px;padding-left:23px;background-color:#fff;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:1px solid #f1f1f1}.theme-pink .layui-layer.layui-layer-admin .layui-layer-setwin a{color:#8c8c8c;font-weight:600}.theme-pink .layui-layer.layui-layer-admin .layui-layer-setwin .layui-layer-min cite{background-color:#8c8c8c}.theme-pink .layui-layer.layui-layer-admin .layui-layer-btn a{height:32px;line-height:32px;border-radius:4px;box-shadow:0 1px 0 rgba(0,0,0,.03)}.theme-pink .layui-layer.layui-layer-admin .layui-layer-btn .layui-layer-btn0{border-color:#fb7299;background-color:#fb7299}.theme-pink .more-theme-item:hover,.theme-pink .more-theme-item.active{border-color:#fb7299}.theme-pink .btn-circle{background:#fb7299}.theme-pink .ball-loader>span,.theme-pink .signal-loader>span{background-color:#fb7299}.theme-pink .text-primary,.theme-pink .layui-link{color:#fb7299!important}.theme-pink .layui-card{border-radius:4px;box-shadow:none}.theme-pink .layui-btn{height:36px;line-height:36px;border-radius:4px;background-color:#fb7299;box-shadow:0 1px 0 rgba(0,0,0,.03)}.theme-pink .layui-btn-lg{height:42px;line-height:42px}.theme-pink .layui-btn-sm{height:28px;line-height:28px}.theme-pink .layui-btn-xs{height:22px;line-height:22px}.theme-pink .layui-input,.theme-pink .layui-select,.theme-pink .layui-textarea,.theme-pink xm-select{height:36px;border-radius:4px}.theme-pink .layui-input:focus,.theme-pink .layui-textarea:focus,.theme-pink xm-select:hover{border-color:#fb7299!important}.theme-pink .layui-form-label,.theme-pink .layui-form-mid{padding-top:8px;padding-bottom:8px}.theme-pink .layui-input-block{min-height:36px}.theme-pink .layui-form-radio{margin-top:4px}.theme-pink .layui-form-onswitch{border-color:#fb7299;background-color:#fb7299}.theme-pink .layui-form-radio>i:hover,.theme-pink .layui-form-radioed>i,.theme-pink .layui-form-checked i,.theme-pink .layui-form-checked:hover i{color:#fb7299}.theme-pink .layui-form-checked[lay-skin=primary] i,.theme-pink .layui-form-checked span,.theme-pink .layui-form-checked:hover span{border-color:#fb7299!important;background-color:#fb7299}.theme-pink .layui-form-checked[lay-skin=primary] i:hover,.theme-pink .layui-form-checkbox[lay-skin=primary]:hover i{border-color:#fb7299!important}.theme-pink .layui-form-select dl dd.layui-this{background-color:#fb7299}.theme-pink .layui-laypage .layui-laypage-curr .layui-laypage-em{background-color:#fb7299}.theme-pink .layui-laypage input:focus,.theme-pink .layui-laypage select:focus{border-color:#fb7299!important}.theme-pink .layui-laypage a:hover{color:#fb7299}.theme-pink .layui-tab-brief>.layui-tab-title .layui-this{color:#fb7299}.theme-pink .layui-tab-brief>.layui-tab-more li.layui-this:after,.theme-pink .layui-tab-brief>.layui-tab-title .layui-this:after{border-color:#fb7299!important}.theme-pink .layui-tab.layui-tab-vertical>.layui-tab-title>li.layui-this{border-color:#fb7299;color:#fb7299}.theme-pink .layui-breadcrumb a:hover{color:#fb7299!important}.theme-pink .layui-laydate-footer span:hover,.theme-pink .layui-laydate-header i:hover,.theme-pink .layui-laydate-header span:hover{color:#fb7299}.theme-pink .layui-laydate .layui-this{background-color:#fb7299!important}.theme-pink .layui-laydate-content td.laydate-selected{background-color:#fff1f5}.theme-pink .laydate-selected:hover{background-color:#fff1f5!important}.theme-pink .layui-timeline-axis{color:#fb7299}.theme-pink .layui-transfer-active .layui-btn{background-color:#fb7299!important;border-color:#fb7299!important}.theme-pink .layui-progress-bar{background-color:#fb7299}.theme-pink .layui-slider-bar{background-color:#fb7299!important}.theme-pink .layui-slider-wrap-btn{border-color:#fb7299!important}.theme-pink .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon{color:#fb7299}.theme-pink .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon.layui-icon-ok,.theme-pink .layui-elem-quote{border-color:#fb7299}.theme-pink .layui-tab.layui-steps>.layui-tab-title>li:before,.theme-pink .layui-tab.layui-steps>.layui-tab-title>li.layui-this>.layui-icon.layui-icon-ok{background-color:#fb7299}.theme-pink .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li{background-color:#fdb8cc}.theme-pink .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this{background-color:#fb7299}.theme-pink .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li:after{border-left-color:#fdb8cc!important}.theme-pink .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this+li:after{border-left-color:#fb7299!important}.theme-pink .ew-cascader-dropdown-list-item.active,.theme-pink .ew-cascader-dropdown-list-item.active .ew-icon-right{color:#fb7299}.theme-pink div.tagsinput span.tag{background:#fb7299}.theme-pink xm-select .xm-body .xm-option .xm-option-icon{border-color:#fb7299!important}.theme-pink xm-select .xm-body .xm-option.selected .xm-option-icon,.theme-pink xm-select>.xm-body .xm-toolbar .toolbar-tag:hover,.theme-pink .ew-xmselect-tree xm-select .xm-body .xm-option.selected .xm-option-content{color:#fb7299!important}.theme-pink xm-select .xm-label .xm-label-block,.theme-pink xm-select .xm-body .xm-option.hide-icon.selected{background-color:#fb7299!important}.theme-pink .city-select a.active{color:#fff!important;background-color:#fb7299!important}.theme-pink .city-select a:hover,.theme-pink .city-select a:focus{background-color:#fff1f5;color:#fb7299}.theme-pink .city-picker-span>.title>span:hover{background-color:#fff1f5}.theme-pink .city-select-tab>a.active{color:#fb7299}.theme-colorful .layui-layout-admin .layui-header .layui-logo{color:#262626;background-color:transparent;box-shadow:2px 8px 8px 0 rgba(29,35,41,.05)}.theme-colorful .layui-layout-admin .layui-header{box-shadow:0 1px 4px rgba(0,21,41,.08)}.theme-colorful .layui-layout-admin .layui-header .layui-nav .layui-this:after,.theme-colorful .layui-layout-admin .layui-header .layui-nav-bar{background-color:#2d8cf0}.theme-colorful .layui-layout-admin .layui-side{background-color:#fff;box-shadow:2px 8px 8px 0 rgba(29,35,41,.05)}.theme-colorful .layui-side .layui-nav .layui-nav-item a{color:#595959}.theme-colorful .layui-side .layui-nav .layui-nav-item a:hover{color:#2d8cf0}.theme-colorful .layui-side .layui-nav-itemed>a,.theme-colorful .layui-side .layui-nav-tree .layui-nav-title a,.theme-colorful .layui-side .layui-nav-tree .layui-nav-title a:hover{color:#595959!important}.theme-colorful .layui-side .layui-nav-itemed>a:hover{color:#2d8cf0!important}.theme-colorful .layui-side .layui-nav-tree .layui-nav-child dd.layui-this a,.theme-colorful .layui-side .layui-nav-tree .layui-this>a,.theme-colorful .layui-side .layui-nav-tree .layui-this>a:hover{color:#2d8cf0;background:#f0faff;border-right:2px solid #2d8cf0}.theme-colorful .layui-side .layui-nav-tree .layui-nav-item .layui-nav-child{background-color:transparent!important}.theme-colorful .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child:before{background:#fff!important}@media screen and (min-width:769px){.theme-colorful .layui-layout-admin.admin-nav-mini .layui-side .layui-nav li.layui-nav-itemed>a{background:#f0faff;color:#2d8cf0!important}}.theme-colorful .layui-nav-tree>.layui-nav-item>a:before{display:none}.theme-colorful .layui-side .layui-nav .layui-nav-more{border-color:rgba(89,89,89,.7) transparent transparent}.theme-colorful .layui-side .layui-nav .layui-nav-mored,.theme-colorful .layui-side .layui-nav-itemed>a .layui-nav-more{border-color:transparent transparent rgba(89,89,89,.7)}.theme-colorful .layui-side .layui-nav-tree.arrow3 .layui-nav-itemed>a>.layui-nav-more:before{background-color:rgba(89,89,89,.7)}@media screen and (min-width:769px){.theme-colorful .layui-layout-admin.admin-nav-mini .layui-side .layui-nav .admin-nav-hover>.layui-nav-child>dd>a .layui-nav-more{border-color:transparent transparent transparent rgba(89,89,89,.7)}}.theme-colorful .layui-side .layui-nav .layui-nav-item a cite{vertical-align:middle}.theme-colorful .layui-side .layui-nav-item>a>.layui-icon{color:#fff;width:28px;height:28px;font-size:12px!important;line-height:28px;text-align:center;border-radius:50%;display:inline-block;vertical-align:middle;background-color:#61b2fc}.theme-colorful .layui-side .layui-nav-item:nth-child(even)>a>.layui-icon{background-color:#7dd733}.theme-colorful .layui-side .layui-nav-item:nth-child(3)>a>.layui-icon{background-color:#32a2d4}.theme-colorful .layui-side .layui-nav-item:nth-child(4)>a>.layui-icon{background-color:#2bccce}.theme-colorful .layui-side .layui-nav-item:nth-child(5)>a>.layui-icon{background-color:#7383cf}@media screen and (min-width:768px){.theme-colorful .admin-nav-mini .layui-side .layui-nav-item>a{padding-left:16px}}.theme-colorful .layui-layout-admin .layui-side .layui-nav .layui-nav-item .layui-nav-child a{padding-left:63px}.theme-colorful .layui-layout-admin .layui-side .layui-nav .layui-nav-item .layui-nav-child .layui-nav-child a{padding-left:83px}.theme-colorful .layui-layout-admin .layui-side .layui-nav .layui-nav-item .layui-nav-child .layui-nav-child .layui-nav-child a{padding-left:103px}.theme-colorful .layui-layout-admin .layui-side .layui-nav .layui-nav-item .layui-nav-child .layui-nav-child .layui-nav-child .layui-nav-child a{padding-left:123px}.theme-colorful .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title{top:8px;right:8px;height:32px;line-height:32px;box-sizing:border-box;background-color:transparent;box-shadow:-4px 4px 0 #f5f7f9;padding-right:70px}.theme-colorful .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li{border:0;margin-right:6px;border-radius:4px;background-color:#fff;line-height:32px;height:32px}.theme-colorful .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this{color:#2d8cf0;background-color:#fff}.theme-colorful .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li:hover{background-color:#fff}.theme-colorful .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li.layui-this:after{display:none}.theme-colorful .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li .layui-tab-close,.theme-colorful .layui-layout-admin .layui-body>.layui-tab>.layui-tab-title li .layui-tab-close:hover{top:8px;color:#8c8c8c;background-color:transparent}.theme-colorful .layui-layout-admin .layui-body .admin-tabs-control,.theme-colorful .layui-layout-admin .layui-body .admin-tabs-control:hover{top:8px;height:32px;line-height:32px;background-color:#f5f7f9;border:0}.theme-colorful .layui-layout-admin .layui-body .admin-tabs-control.layui-icon-down{border-radius:4px;background-color:#fff;width:32px;right:8px}.theme-colorful .admin-tabs-control>.layui-nav .layui-nav-item{line-height:32px}.theme-colorful .admin-tabs-control>.layui-nav .layui-nav-item>a{height:32px;width:32px;padding:0}.theme-colorful .admin-tabs-control>.layui-nav .layui-nav-child{top:36px;border:0;border-radius:4px;box-shadow:0 1px 6px rgba(0,0,0,.2)}.theme-colorful .layui-layout-admin .layui-body .admin-tabs-control.layui-icon-prev:before{content:"\e603"}.theme-colorful .layui-layout-admin .layui-body .admin-tabs-control.layui-icon-next:before{content:"\e602"}.theme-colorful .layui-body-header-title{border-left-color:#2d8cf0}.theme-colorful .layui-body-header{box-shadow:0 1px 4px rgba(0,21,41,.08)}.theme-colorful .layui-layer.layui-layer-admin{border-radius:4px}.theme-colorful .layui-layer.layui-layer-admin .layui-layer-title{color:#262626;font-size:16px;padding-left:23px;background-color:#fff;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:1px solid #f1f1f1}.theme-colorful .layui-layer.layui-layer-admin .layui-layer-setwin a{color:#8c8c8c;font-weight:600}.theme-colorful .layui-layer.layui-layer-admin .layui-layer-setwin .layui-layer-min cite{background-color:#8c8c8c}.theme-colorful .layui-layer.layui-layer-admin .layui-layer-btn a{height:32px;line-height:32px;border-radius:4px;box-shadow:0 1px 0 rgba(0,0,0,.03)}.theme-colorful .layui-layer.layui-layer-admin .layui-layer-btn .layui-layer-btn0{border-color:#2d8cf0;background-color:#2d8cf0}.theme-colorful .more-theme-item:hover,.theme-colorful .more-theme-item.active{border-color:#2d8cf0}.theme-colorful .btn-circle{background:#2d8cf0}.theme-colorful .ball-loader>span,.theme-colorful .signal-loader>span{background-color:#2d8cf0}.theme-colorful .text-primary,.theme-colorful .layui-link{color:#2d8cf0!important}.theme-colorful .layui-card{border-radius:4px;box-shadow:none}.theme-colorful .layui-btn{height:36px;line-height:36px;border-radius:4px;background-color:#2d8cf0;box-shadow:0 1px 0 rgba(0,0,0,.03)}.theme-colorful .layui-btn-lg{height:42px;line-height:42px}.theme-colorful .layui-btn-sm{height:28px;line-height:28px}.theme-colorful .layui-btn-xs{height:22px;line-height:22px}.theme-colorful .layui-input,.theme-colorful .layui-select,.theme-colorful .layui-textarea,.theme-colorful xm-select{height:36px;border-radius:4px}.theme-colorful .layui-input:focus,.theme-colorful .layui-textarea:focus,.theme-colorful xm-select:hover{border-color:#2d8cf0!important}.theme-colorful .layui-form-label,.theme-colorful .layui-form-mid{padding-top:8px;padding-bottom:8px}.theme-colorful .layui-input-block{min-height:36px}.theme-colorful .layui-form-radio{margin-top:4px}.theme-colorful .layui-form-onswitch{border-color:#2d8cf0;background-color:#2d8cf0}.theme-colorful .layui-form-radio>i:hover,.theme-colorful .layui-form-radioed>i,.theme-colorful .layui-form-checked i,.theme-colorful .layui-form-checked:hover i{color:#2d8cf0}.theme-colorful .layui-form-checked[lay-skin=primary] i,.theme-colorful .layui-form-checked span,.theme-colorful .layui-form-checked:hover span{border-color:#2d8cf0!important;background-color:#2d8cf0}.theme-colorful .layui-form-checkbox[lay-skin=primary] i:hover,.theme-colorful .layui-form-checkbox[lay-skin=primary]:hover i{border-color:#2d8cf0}.theme-colorful .layui-form-select dl dd.layui-this{background-color:#2d8cf0}.theme-colorful .layui-laypage .layui-laypage-curr .layui-laypage-em{background-color:#2d8cf0}.theme-colorful .layui-laypage input:focus,.theme-colorful .layui-laypage select:focus{border-color:#2d8cf0!important}.theme-colorful .layui-laypage a:hover{color:#2d8cf0}.theme-colorful .layui-tab-brief>.layui-tab-title .layui-this{color:#2d8cf0}.theme-colorful .layui-tab-brief>.layui-tab-more li.layui-this:after,.theme-colorful .layui-tab-brief>.layui-tab-title .layui-this:after{border-color:#2d8cf0!important}.theme-colorful .layui-tab.layui-tab-vertical>.layui-tab-title>li.layui-this{border-color:#2d8cf0;color:#2d8cf0}.theme-colorful .layui-breadcrumb a:hover{color:#2d8cf0!important}.theme-colorful .layui-laydate-footer span:hover,.theme-colorful .layui-laydate-header i:hover,.theme-colorful .layui-laydate-header span:hover{color:#2d8cf0}.theme-colorful .layui-laydate .layui-this{background-color:#2d8cf0!important}.theme-colorful .layui-laydate-content td.laydate-selected{background-color:rgba(45,140,240,.1)}.theme-colorful .laydate-selected:hover{background-color:rgba(45,140,240,.1)!important}.theme-colorful .layui-timeline-axis{color:#2d8cf0}.theme-colorful .layui-transfer-active .layui-btn{background-color:#2d8cf0!important;border-color:#2d8cf0!important}.theme-colorful .layui-progress-bar{background-color:#2d8cf0}.theme-colorful .layui-slider-bar{background-color:#2d8cf0!important}.theme-colorful .layui-slider-wrap-btn{border-color:#2d8cf0!important}.theme-colorful .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon{color:#2d8cf0}.theme-colorful .layui-tab.layui-steps>.layui-tab-title>li>.layui-icon.layui-icon-ok,.theme-colorful .layui-elem-quote{border-color:#2d8cf0}.theme-colorful .layui-tab.layui-steps>.layui-tab-title>li:before,.theme-colorful .layui-tab.layui-steps>.layui-tab-title>li.layui-this>.layui-icon.layui-icon-ok{background-color:#2d8cf0}.theme-colorful .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li{background-color:#96c6f8}.theme-colorful .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this{background-color:#2d8cf0}.theme-colorful .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li:after{border-left-color:#96c6f8!important}.theme-colorful .layui-tab.layui-steps.layui-steps-simple>.layui-tab-title>li.layui-this+li:after{border-left-color:#2d8cf0!important}.theme-colorful .ew-cascader-dropdown-list-item.active,.theme-colorful .ew-cascader-dropdown-list-item.active .ew-icon-right{color:#2d8cf0}.theme-colorful div.tagsinput span.tag{background:#2d8cf0}.theme-colorful xm-select .xm-body .xm-option .xm-option-icon{border-color:#2d8cf0!important}.theme-colorful xm-select .xm-body .xm-option.selected .xm-option-icon,.theme-colorful xm-select>.xm-body .xm-toolbar .toolbar-tag:hover,.theme-colorful .ew-xmselect-tree xm-select .xm-body .xm-option.selected .xm-option-content{color:#2d8cf0!important}.theme-colorful xm-select .xm-label .xm-label-block,.theme-colorful xm-select .xm-body .xm-option.hide-icon.selected{background-color:#2d8cf0!important}.theme-colorful .city-select a.active{color:#fff!important;background-color:#2d8cf0!important}.theme-colorful .city-select a:hover,.theme-colorful .city-select a:focus{background-color:#f0faff;color:#2d8cf0}.theme-colorful .city-picker-span>.title>span:hover{background-color:#f0faff}.theme-colorful .city-select-tab>a.active{color:#2d8cf0} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/css/login2/login2.css b/ss-admin/src/main/resources/static/css/login2/login2.css new file mode 100644 index 0000000..5018240 --- /dev/null +++ b/ss-admin/src/main/resources/static/css/login2/login2.css @@ -0,0 +1,143 @@ +body { + background-image: url("/images/bg-login.jpg"); + background-repeat: no-repeat; + background-size: cover; + min-height: 100vh; +} + +body:before { + content: ""; + background-color: rgba(0, 0, 0, .2); + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.login-wrapper { + max-width: 420px; + padding: 20px; + margin: 0 auto; + position: relative; + box-sizing: border-box; + z-index: 2; +} + +.login-wrapper > .layui-form { + padding: 25px 30px; + background-color: #fff; + box-shadow: 0 3px 6px -1px rgba(0, 0, 0, 0.19); + box-sizing: border-box; + border-radius: 4px; +} + +.login-wrapper > .layui-form > h2 { + color: #333; + font-size: 18px; + text-align: center; + margin-bottom: 25px; +} + +.login-wrapper > .layui-form > .layui-form-item { + margin-bottom: 25px; + position: relative; +} + +.login-wrapper > .layui-form > .layui-form-item:last-child { + margin-bottom: 0; +} + +.login-wrapper > .layui-form > .layui-form-item > .layui-input { + height: 46px; + line-height: 1; + border-radius: 2px !important; +} + +.login-wrapper .layui-input-icon-group > .layui-input { + padding-left: 46px; +} + +.login-wrapper .layui-input-icon-group > .layui-icon { + width: 46px; + height: 46px; + line-height: 46px; + font-size: 20px; + color: #909399; + position: absolute; + left: 0; + top: 0; + text-align: center; +} + +.login-wrapper > .layui-form > .layui-form-item.login-captcha-group { + padding-right: 135px; +} + +.login-wrapper > .layui-form > .layui-form-item.login-captcha-group > .login-captcha { + height: 46px; + width: 120px; + cursor: pointer; + box-sizing: border-box; + border: 1px solid #e6e6e6; + border-radius: 2px !important; + position: absolute; + right: 0; + top: 0; +} + +.login-wrapper > .layui-form > .layui-form-item > .layui-form-checkbox { + margin: 0 !important; + padding-left: 25px; +} + +.login-wrapper > .layui-form > .layui-form-item > .layui-form-checkbox > .layui-icon { + width: 15px !important; + height: 15px !important; +} + +.login-wrapper > .layui-form .layui-btn-fluid { + height: 48px; + line-height: 48px; + font-size: 16px; + border-radius: 2px !important; +} + +.login-wrapper > .layui-form > .layui-form-item.login-oauth-group > a > .layui-icon { + font-size: 26px; +} + +.login-copyright { + color: #eee; + padding-bottom: 20px; + text-align: center; + position: relative; + z-index: 1; +} + +@media screen and (min-height: 550px) { + .login-wrapper { + margin: -250px auto 0; + position: absolute; + top: 50%; + left: 0; + right: 0; + width: 100%; + } + + .login-copyright { + position: absolute; + bottom: 0; + right: 0; + left: 0; + } +} + +.layui-btn { + background-color: #5FB878; + border-color: #5FB878; +} + +.layui-link { + color: #5FB878 !important; +} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/css/public.css b/ss-admin/src/main/resources/static/css/public.css new file mode 100644 index 0000000..9218d83 --- /dev/null +++ b/ss-admin/src/main/resources/static/css/public.css @@ -0,0 +1,114 @@ +body { + margin: 15px 15px 15px 15px; + background: #f2f2f2; +} + +.layuimini-container { + border: 1px solid #f2f2f2; + border-radius: 5px; + background-color: #ffffff +} + +.layuimini-main { + margin: 10px 10px 10px 10px; +} + +/**必填红点 */ +.layuimini-form > .layui-form-item > .required:after { + content: '*'; + color: red; + position: absolute; + margin-left: 4px; + font-weight: bold; + line-height: 1.8em; + top: 6px; + right: 5px; +} + +.layuimini-form > .layui-form-item > .layui-form-label { + width: 120px !important; +} + +.layuimini-form > .layui-form-item > .layui-input-block { + margin-left: 150px !important; +} + +.layuimini-form > .layui-form-item > .layui-input-block > tip { + display: inline-block; + margin-top: 10px; + line-height: 10px; + font-size: 10px; + color: #a29c9c; +} + +/**搜索框*/ +.layuimini-container .table-search-fieldset { + margin: 0; + border: 1px solid #e6e6e6; + padding: 10px 20px 5px 20px; + color: #6b6b6b; +} + +/**自定义滚动条样式 */ +::-webkit-scrollbar { + width: 6px; + height: 6px +} + +::-webkit-scrollbar-track { + background-color: transparent; + -webkit-border-radius: 2em; + -moz-border-radius: 2em; + border-radius: 2em; +} + +::-webkit-scrollbar-thumb { + background-color: #9c9da0; + -webkit-border-radius: 2em; + -moz-border-radius: 2em; + border-radius: 2em +} + +/* 树形选择器 */ +.selectContent { + display: none; + position: absolute; + z-index: 999; + padding-bottom: 4px; + overflow-y: scroll; + max-height: 210px; + background-color: #FAFAFA; + border: 1px solid rgb(204, 204, 204); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.select-tree { + cursor: pointer; +} + +.select-tree + .layui-edge { + position: absolute; + right: 10px; + top: 50%; + margin-top: -3px; + border-width: 6px; + border-top: 6px solid #c2c2c2; +} + +/*树状图下拉框样式*/ +.trg{ + width: 0; + height: 0; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 6px solid black;; + position: absolute; + left:181px; + top:8px; + +} +.org-select{ + cursor: default; + z-index: -1; + width:200px; +} diff --git a/ss-admin/src/main/resources/static/css/themes/default.css b/ss-admin/src/main/resources/static/css/themes/default.css new file mode 100644 index 0000000..8f55edb --- /dev/null +++ b/ss-admin/src/main/resources/static/css/themes/default.css @@ -0,0 +1,98 @@ +/*头部右侧背景色 headerRightBg */ +.layui-layout-admin .layui-header { + background-color: #ffffff !important; +} + +/*头部右侧选中背景色 headerRightBgThis */ +.layui-layout-admin .layui-header .layuimini-header-content > ul > .layui-nav-item.layui-this, .layuimini-tool i:hover { + background-color: #e4e4e4 !important; +} + +/*头部右侧字体颜色 headerRightColor */ +.layui-layout-admin .layui-header .layui-nav .layui-nav-item a { + color: rgba(107, 107, 107, 0.7); +} + +/**头部右侧下拉字体颜色 headerRightChildColor */ +.layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child a { + color: rgba(107, 107, 107, 0.7) !important; +} + +/*头部右侧鼠标选中 headerRightColorThis */ +.layui-header .layuimini-menu-header-pc.layui-nav .layui-nav-item a:hover, .layui-header .layuimini-header-menu.layuimini-pc-show.layui-nav .layui-this a { + color: #565656 !important; +} + +/*头部右侧更多下拉颜色 headerRightNavMore */ +.layui-header .layui-nav .layui-nav-more { + border-top-color: rgba(160, 160, 160, 0.7) !important; +} + +/*头部右侧更多下拉颜色 headerRightNavMore */ +.layui-header .layui-nav .layui-nav-mored, .layui-header .layui-nav-itemed > a .layui-nav-more { + border-color: transparent transparent rgba(160, 160, 160, 0.7) !important; +} + +/**头部右侧更多下拉配置色 headerRightNavMoreBg headerRightNavMoreColor */ +.layui-header .layui-nav .layui-nav-child dd.layui-this a, .layui-header .layui-nav-child dd.layui-this, .layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child .layui-this a { + background-color: #154d96 !important; + color: #ffffff !important; +} + +/*头部缩放按钮样式 headerRightToolColor */ +.layui-layout-admin .layui-header .layuimini-tool i { + color: #565656; +} + +/*logo背景颜色 headerLogoBg */ +.layui-layout-admin .layuimini-logo { + background-color: #ffffff !important; +} + +/*logo字体颜色 headerLogoColor */ +.layui-layout-admin .layuimini-logo h1 { + color: rgb(191, 187, 187); +} + +/*左侧菜单更多下拉样式 leftMenuNavMore */ +.layuimini-menu-left .layui-nav .layui-nav-more, .layuimini-menu-left-zoom.layui-nav .layui-nav-more { + border-top-color: rgb(191, 187, 187); +} + +/*左侧菜单更多下拉样式 leftMenuNavMore */ +.layuimini-menu-left .layui-nav .layui-nav-mored, .layuimini-menu-left .layui-nav-itemed > a .layui-nav-more, .layuimini-menu-left-zoom.layui-nav .layui-nav-mored, .layuimini-menu-left-zoom.layui-nav-itemed > a .layui-nav-more { + border-color: transparent transparent rgb(191, 187, 187) !important; +} + +/*左侧菜单背景 leftMenuBg */ +.layui-side.layui-bg-black, .layui-side.layui-bg-black > .layuimini-menu-left > ul, .layuimini-menu-left-zoom > ul { + background-color: #ffffff !important; +} + +/*左侧菜单选中背景 leftMenuBgThis */ +.layuimini-menu-left .layui-nav-tree .layui-this, .layuimini-menu-left .layui-nav-tree .layui-this > a, .layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this, .layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this a, .layuimini-menu-left-zoom.layui-nav-tree .layui-this, .layuimini-menu-left-zoom.layui-nav-tree .layui-this > a, .layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this, .layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this a { + background-color: #154d96 !important +} + +/*左侧菜单子菜单背景 leftMenuChildBg */ +.layuimini-menu-left .layui-nav-itemed > .layui-nav-child { + background-color: #ffffff !important; +} + +/*左侧菜单字体颜色 leftMenuColor */ +.layuimini-menu-left .layui-nav .layui-nav-item a, .layuimini-menu-left-zoom.layui-nav .layui-nav-item a { + color: rgb(40, 31, 31) !important; +} + +/*左侧菜单选中字体颜色 leftMenuColorThis */ +.layuimini-menu-left , .layuimini-menu-left .layui-nav .layui-this a, .layuimini-menu-left-zoom.layui-nav .layui-this a { + color: #fac45f !important; +} +.layui-nav .layui-nav-item a:hover, .layuimini-menu-left-zoom.layui-nav .layui-nav-item a:hover{ + color: #fac45f !important; +} + +/**tab选项卡选中颜色 tabActiveColor */ +.layuimini-tab .layui-tab-title .layui-this .layuimini-tab-active { + background-color: #1e9fff; +} diff --git a/ss-admin/src/main/resources/static/css/welcome.css b/ss-admin/src/main/resources/static/css/welcome.css new file mode 100644 index 0000000..b84d495 --- /dev/null +++ b/ss-admin/src/main/resources/static/css/welcome.css @@ -0,0 +1,136 @@ +.layui-card { + border: 1px solid #f2f2f2; + border-radius: 5px; +} + +.icon { + margin-right: 10px; + color: #1aa094; +} + +.icon-cray { + color: #ffb800 !important; +} + +.icon-blue { + color: #1e9fff !important; +} + +.icon-tip { + color: #ff5722 !important; +} + +.layuimini-qiuck-module { + text-align: center; + margin-top: 10px +} + +.layuimini-qiuck-module a i { + display: inline-block; + width: 100%; + height: 70px; + line-height: 70px; + text-align: center; + border-radius: 2px; + font-size: 30px; + background-color: #F8F8F8; + color: #333; + transition: all .3s; + -webkit-transition: all .3s; +} + +.layuimini-qiuck-module a cite { + position: relative; + top: 2px; + display: block; + color: #666; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + font-size: 14px; +} + +.welcome-module { + width: 100%; + height: 115px; +} + +.panel { + background-color: #fff; + border: 1px solid transparent; + border-radius: 3px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: 0 1px 1px rgba(0, 0, 0, .05) +} + +.panel-body { + padding: 10px +} + +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 12px; + color: inherit +} + +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: 700; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; + margin-top: .3em; +} + +.layui-red { + color: red +} + +.main_btn > p { + height: 40px; +} + +.layui-bg-number { + background-color: #F8F8F8; +} + +.layuimini-notice:hover { + background: #f6f6f6; +} + +.layuimini-notice { + padding: 7px 16px; + clear: both; + font-size: 12px !important; + cursor: pointer; + position: relative; + transition: background 0.2s ease-in-out; +} + +.layuimini-notice-title, .layuimini-notice-label { + padding-right: 70px !important; + text-overflow: ellipsis !important; + overflow: hidden !important; + white-space: nowrap !important; +} + +.layuimini-notice-title { + line-height: 28px; + font-size: 14px; +} + +.layuimini-notice-extra { + position: absolute; + top: 50%; + margin-top: -8px; + right: 16px; + display: inline-block; + height: 16px; + color: #999; +} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/data/123.pptx b/ss-admin/src/main/resources/static/data/123.pptx new file mode 100644 index 0000000..b8d8470 Binary files /dev/null and b/ss-admin/src/main/resources/static/data/123.pptx differ diff --git a/ss-admin/src/main/resources/static/data/data.html b/ss-admin/src/main/resources/static/data/data.html new file mode 100644 index 0000000..ef97334 --- /dev/null +++ b/ss-admin/src/main/resources/static/data/data.html @@ -0,0 +1,33 @@ +{"code":0,"msg":"PDF","count":1000, +"data":[ +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""}, +{"id":0,"username":"公司规章制度","city":"2026-01-02 00:00:00","sign":"张三","experience":255,"logins":24,"wealth":82830700,"classify":"PDF","score":""} +]} diff --git a/ss-admin/src/main/resources/static/images/bg-login.jpg b/ss-admin/src/main/resources/static/images/bg-login.jpg new file mode 100644 index 0000000..8caec45 Binary files /dev/null and b/ss-admin/src/main/resources/static/images/bg-login.jpg differ diff --git a/ss-admin/src/main/resources/static/images/bg.jpg b/ss-admin/src/main/resources/static/images/bg.jpg new file mode 100644 index 0000000..d5870f5 Binary files /dev/null and b/ss-admin/src/main/resources/static/images/bg.jpg differ diff --git a/ss-admin/src/main/resources/static/images/captcha.jpg b/ss-admin/src/main/resources/static/images/captcha.jpg new file mode 100644 index 0000000..92b2a33 Binary files /dev/null and b/ss-admin/src/main/resources/static/images/captcha.jpg differ diff --git a/ss-admin/src/main/resources/static/images/donate_qrcode.png b/ss-admin/src/main/resources/static/images/donate_qrcode.png new file mode 100644 index 0000000..079ac3d Binary files /dev/null and b/ss-admin/src/main/resources/static/images/donate_qrcode.png differ diff --git a/ss-admin/src/main/resources/static/images/favicon.ico b/ss-admin/src/main/resources/static/images/favicon.ico new file mode 100644 index 0000000..afa0548 Binary files /dev/null and b/ss-admin/src/main/resources/static/images/favicon.ico differ diff --git a/ss-admin/src/main/resources/static/images/favicon2.ico b/ss-admin/src/main/resources/static/images/favicon2.ico new file mode 100644 index 0000000..afa0548 Binary files /dev/null and b/ss-admin/src/main/resources/static/images/favicon2.ico differ diff --git a/ss-admin/src/main/resources/static/images/home.png b/ss-admin/src/main/resources/static/images/home.png new file mode 100644 index 0000000..348ff27 Binary files /dev/null and b/ss-admin/src/main/resources/static/images/home.png differ diff --git a/ss-admin/src/main/resources/static/images/ic_404.png b/ss-admin/src/main/resources/static/images/ic_404.png new file mode 100644 index 0000000..e2eb683 Binary files /dev/null and b/ss-admin/src/main/resources/static/images/ic_404.png differ diff --git a/ss-admin/src/main/resources/static/images/icon-login.png b/ss-admin/src/main/resources/static/images/icon-login.png new file mode 100644 index 0000000..1db2f96 Binary files /dev/null and b/ss-admin/src/main/resources/static/images/icon-login.png differ diff --git a/ss-admin/src/main/resources/static/images/loginbg.png b/ss-admin/src/main/resources/static/images/loginbg.png new file mode 100644 index 0000000..675c74b Binary files /dev/null and b/ss-admin/src/main/resources/static/images/loginbg.png differ diff --git a/ss-admin/src/main/resources/static/images/logo.png b/ss-admin/src/main/resources/static/images/logo.png new file mode 100644 index 0000000..d184366 Binary files /dev/null and b/ss-admin/src/main/resources/static/images/logo.png differ diff --git a/ss-admin/src/main/resources/static/images/logo/logo.png b/ss-admin/src/main/resources/static/images/logo/logo.png new file mode 100644 index 0000000..50b706d Binary files /dev/null and b/ss-admin/src/main/resources/static/images/logo/logo.png differ diff --git a/ss-admin/src/main/resources/static/images/logo/logo2.ico b/ss-admin/src/main/resources/static/images/logo/logo2.ico new file mode 100644 index 0000000..37c881a Binary files /dev/null and b/ss-admin/src/main/resources/static/images/logo/logo2.ico differ diff --git a/ss-admin/src/main/resources/static/images/logo/logo2.png b/ss-admin/src/main/resources/static/images/logo/logo2.png new file mode 100644 index 0000000..37c881a Binary files /dev/null and b/ss-admin/src/main/resources/static/images/logo/logo2.png differ diff --git a/ss-admin/src/main/resources/static/images/logo2.png b/ss-admin/src/main/resources/static/images/logo2.png new file mode 100644 index 0000000..fb2062e Binary files /dev/null and b/ss-admin/src/main/resources/static/images/logo2.png differ diff --git a/ss-admin/src/main/resources/static/js/jquery-1.10.2.min.js b/ss-admin/src/main/resources/static/js/jquery-1.10.2.min.js new file mode 100644 index 0000000..76d21a4 --- /dev/null +++ b/ss-admin/src/main/resources/static/js/jquery-1.10.2.min.js @@ -0,0 +1,6 @@ +/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery-1.10.2.min.map +*/ +(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="
",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
t
",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t +}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); +u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("'); + }, + + /** + * 初始化缓存地址 + * @param clearUrl + */ + renderClear: function (clearUrl) { + $('.layuimini-clear').attr('data-href',clearUrl); + }, + + /** + * 初始化iframe窗口动画 + * @param anim + */ + renderAnim: function (anim) { + if (anim) { + $('#layuimini-bg-color').after(''); + } + }, + + fullScreen: function () { + var el = document.documentElement; + var rfs = el.requestFullScreen || el.webkitRequestFullScreen; + if (typeof rfs != "undefined" && rfs) { + rfs.call(el); + } else if (typeof window.ActiveXObject != "undefined") { + var wscript = new ActiveXObject("WScript.Shell"); + if (wscript != null) { + wscript.SendKeys("{F11}"); + } + } else if (el.msRequestFullscreen) { + el.msRequestFullscreen(); + } else if (el.oRequestFullscreen) { + el.oRequestFullscreen(); + } else if (el.webkitRequestFullscreen) { + el.webkitRequestFullscreen(); + } else if (el.mozRequestFullScreen) { + el.mozRequestFullScreen(); + } else { + miniAdmin.error('浏览器不支持全屏调用!'); + } + }, + + /** + * 退出全屏 + */ + exitFullScreen: function () { + var el = document; + var cfs = el.cancelFullScreen || el.webkitCancelFullScreen || el.exitFullScreen; + if (typeof cfs != "undefined" && cfs) { + cfs.call(el); + } else if (typeof window.ActiveXObject != "undefined") { + var wscript = new ActiveXObject("WScript.Shell"); + if (wscript != null) { + wscript.SendKeys("{F11}"); + } + } else if (el.msExitFullscreen) { + el.msExitFullscreen(); + } else if (el.oRequestFullscreen) { + el.oCancelFullScreen(); + }else if (el.mozCancelFullScreen) { + el.mozCancelFullScreen(); + } else if (el.webkitCancelFullScreen) { + el.webkitCancelFullScreen(); + } else { + miniAdmin.error('浏览器不支持全屏调用!'); + } + }, + + /** + * 初始化设备端 + */ + renderDevice: function () { + if (miniAdmin.checkMobile()) { + $('.layuimini-tool i').attr('data-side-fold', 1); + $('.layuimini-tool i').attr('class', 'fa fa-outdent'); + $('.layui-layout-body').removeClass('layuimini-mini'); + $('.layui-layout-body').addClass('layuimini-all'); + } + }, + + + /** + * 初始化加载时间 + * @param loadingTime + */ + deleteLoader: function (loadingTime) { + setTimeout(function () { + $('.layuimini-loader').fadeOut(); + }, loadingTime * 1000) + }, + + /** + * 成功 + * @param title + * @returns {*} + */ + success: function (title) { + return layer.msg(title, {icon: 1, shade: this.shade, scrollbar: false, time: 2000, shadeClose: true}); + }, + + /** + * 失败 + * @param title + * @returns {*} + */ + error: function (title) { + return layer.msg(title, {icon: 2, shade: this.shade, scrollbar: false, time: 3000, shadeClose: true}); + }, + + /** + * 判断是否为手机 + * @returns {boolean} + */ + checkMobile: function () { + var ua = navigator.userAgent.toLocaleLowerCase(); + var pf = navigator.platform.toLocaleLowerCase(); + var isAndroid = (/android/i).test(ua) || ((/iPhone|iPod|iPad/i).test(ua) && (/linux/i).test(pf)) + || (/ucweb.*linux/i.test(ua)); + var isIOS = (/iPhone|iPod|iPad/i).test(ua) && !isAndroid; + var isWinPhone = (/Windows Phone|ZuneWP7/i).test(ua); + var clientWidth = document.documentElement.clientWidth; + if (!isAndroid && !isIOS && !isWinPhone && clientWidth > 1024) { + return false; + } else { + return true; + } + }, + + /** + * 监听 + */ + listen: function () { + + /** + * 清理 + */ + $('body').on('click', '[data-clear]', function () { + var loading = layer.load(0, {shade: false, time: 2 * 1000}); + sessionStorage.clear(); + + // 判断是否清理服务端 + var clearUrl = $(this).attr('data-href'); + if (clearUrl != undefined && clearUrl != '' && clearUrl != null) { + $.getJSON(clearUrl, function (data, status) { + layer.close(loading); + if (data.code != 1) { + return miniAdmin.error(data.msg); + } else { + return miniAdmin.success(data.msg); + } + }).fail(function () { + layer.close(loading); + return miniAdmin.error('清理缓存接口有误'); + }); + } else { + layer.close(loading); + return miniAdmin.success('清除缓存成功'); + } + }); + + /** + * 刷新 + */ + $('body').on('click', '[data-refresh]', function () { + $(".layui-tab-item.layui-show").find("iframe")[0].contentWindow.location.reload(); + miniAdmin.success('刷新成功'); + }); + + /** + * 监听提示信息 + */ + $("body").on("mouseenter", ".layui-nav-tree .menu-li", function () { + if (miniAdmin.checkMobile()) { + return false; + } + var classInfo = $(this).attr('class'), + tips = $(this).prop("innerHTML"), + isShow = $('.layuimini-tool i').attr('data-side-fold'); + if (isShow == 0 && tips) { + tips = "
  • "+tips+"
" ; + window.openTips = layer.tips(tips, $(this), { + tips: [2, '#2f4056'], + time: 300000, + skin:"popup-tips", + success:function (el) { + var left = $(el).position().left - 10 ; + $(el).css({ left:left }); + element.render(); + } + }); + } + }); + + $("body").on("mouseleave", ".popup-tips", function () { + if (miniAdmin.checkMobile()) { + return false; + } + var isShow = $('.layuimini-tool i').attr('data-side-fold'); + if (isShow == 0) { + try { + layer.close(window.openTips); + } catch (e) { + console.log(e.message); + } + } + }); + + + /** + * 全屏 + */ + $('body').on('click', '[data-check-screen]', function () { + var check = $(this).attr('data-check-screen'); + if (check == 'full') { + miniAdmin.fullScreen(); + $(this).attr('data-check-screen', 'exit'); + $(this).html(''); + } else { + miniAdmin.exitFullScreen(); + $(this).attr('data-check-screen', 'full'); + $(this).html(''); + } + }); + + /** + * 点击遮罩层 + */ + $('body').on('click', '.layuimini-make', function () { + miniAdmin.renderDevice(); + }); + + } + }; + + + exports("miniAdmin", miniAdmin); +}); diff --git a/ss-admin/src/main/resources/static/js/lay-module/layuimini/miniMenu.js b/ss-admin/src/main/resources/static/js/lay-module/layuimini/miniMenu.js new file mode 100644 index 0000000..507eae3 --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/layuimini/miniMenu.js @@ -0,0 +1,250 @@ +/** + * date:2020/02/27 + * author:Mr.Chung + * version:2.0 + * description:layuimini 菜单框架扩展 + */ +layui.define(["element","laytpl" ,"jquery"], function (exports) { + var element = layui.element, + $ = layui.$, + laytpl = layui.laytpl, + layer = layui.layer; + + var miniMenu = { + + /** + * 菜单初始化 + * @param options.menuList 菜单数据信息 + * @param options.multiModule 是否开启多模块 + * @param options.menuChildOpen 是否展开子菜单 + */ + render: function (options) { + options.menuList = options.menuList || []; + options.multiModule = options.multiModule || false; + options.menuChildOpen = options.menuChildOpen || false; + if (options.multiModule) { + miniMenu.renderMultiModule(options.menuList, options.menuChildOpen); + } else { + miniMenu.renderSingleModule(options.menuList, options.menuChildOpen); + } + miniMenu.listen(); + }, + + /** + * 单模块 + * @param menuList 菜单数据 + * @param menuChildOpen 是否默认展开 + */ + renderSingleModule: function (menuList, menuChildOpen) { + menuList = menuList || []; + var leftMenuHtml = '', + childOpenClass = '', + leftMenuCheckDefault = 'layui-this'; + var me = this ; + if (menuChildOpen) childOpenClass = ' layui-nav-itemed'; + leftMenuHtml = this.renderLeftMenu(menuList,{ childOpenClass:childOpenClass }) ; + $('.layui-layout-body').addClass('layuimini-single-module'); //单模块标识 + $('.layuimini-header-menu').remove(); + $('.layuimini-menu-left').html(leftMenuHtml); + + element.init(); + }, + + /** + * 渲染一级菜单 + */ + compileMenu: function(menu,isSub){ + var menuHtml = '' ; + if(isSub){ + menuHtml = '' + } + return laytpl(menuHtml).render(menu); + }, + compileMenuContainer :function(menu,isSub){ + var wrapperHtml = '
    {{d.children}}
' ; + if(isSub){ + wrapperHtml = '
{{d.children}}
' ; + } + if(!menu.children){ + return ""; + } + return laytpl(wrapperHtml).render(menu); + }, + + each:function(list,callback){ + var _list = []; + for(var i = 0 ,length = list.length ; i= options.maxTabNum) { + layer.msg('Tab窗口已达到限定数量,请先关闭部分Tab'); + return false; + } + var ele = element; + if (options.isIframe) ele = parent.layui.element; + ele.tabAdd('layuiminiTab', { + title: '' + options.title + '' //用于演示 + , content: '' + , id: options.tabId + }); + $('.layuimini-menu-left').attr('layuimini-tab-tag', 'add'); + sessionStorage.setItem('layuiminimenu_' + options.tabId, options.title); + }, + + + /** + * 切换选项卡 + * @param tabId + */ + change: function (tabId) { + element.tabChange('layuiminiTab', tabId); + }, + + /** + * 删除tab窗口 + * @param tabId + * @param isParent + */ + delete: function (tabId, isParent) { + // 未知BUG,不知道是不是layui问题,必须先删除元素 + $(".layuimini-tab .layui-tab-title .layui-unselect.layui-tab-bar").remove(); + + if (isParent === true) { + parent.layui.element.tabDelete('layuiminiTab', tabId); + } else { + element.tabDelete('layuiminiTab', tabId); + } + }, + + /** + * 在iframe层打开新tab方法 + */ + openNewTabByIframe: function (options) { + options.href = options.href || null; + options.title = options.title || null; + var loading = parent.layer.load(0, {shade: false, time: 2 * 1000}); + if (options.href === null || options.href === undefined) options.href = new Date().getTime(); + var checkTab = miniTab.check(options.href, true); + if (!checkTab) { + miniTab.create({ + tabId: options.href, + href: options.href, + title: options.title, + isIframe: true, + }); + } + parent.layui.element.tabChange('layuiminiTab', options.href); + parent.layer.close(loading); + }, + + /** + * 在iframe层关闭当前tab方法 + */ + deleteCurrentByIframe: function () { + var ele = $(".layuimini-tab .layui-tab-title li.layui-this", parent.document); + if (ele.length > 0) { + var layId = $(ele[0]).attr('lay-id'); + miniTab.delete(layId, true); + } + }, + + /** + * 判断tab窗口 + */ + check: function (tabId, isIframe) { + // 判断选项卡上是否有 + var checkTab = false; + if (isIframe === undefined || isIframe === false) { + $(".layui-tab-title li").each(function () { + var checkTabId = $(this).attr('lay-id'); + if (checkTabId != null && checkTabId === tabId) { + checkTab = true; + } + }); + } else { + parent.layui.$(".layui-tab-title li").each(function () { + var checkTabId = $(this).attr('lay-id'); + if (checkTabId != null && checkTabId === tabId) { + checkTab = true; + } + }); + } + return checkTab; + }, + + /** + * 开启tab右键菜单 + * @param tabId + * @param left + */ + openTabRignMenu: function (tabId, left) { + miniTab.closeTabRignMenu(); + var menuHtml = '
\n' + + '
\n' + + '
关闭当前
\n' + + '
关闭其他
\n' + + '
关闭全部
\n' + + '
\n' + + '
'; + var makeHtml = '
'; + $('.layuimini-tab .layui-tab-title').after(menuHtml); + $('.layuimini-tab .layui-tab-content').after(makeHtml); + }, + + /** + * 关闭tab右键菜单 + */ + closeTabRignMenu: function () { + $('.layuimini-tab-mousedown').remove(); + $('.layuimini-tab-make').remove(); + }, + + /** + * 查询菜单信息 + * @param href + * @param menuList + */ + searchMenu: function (href, menuList) { + var menu; + for (key in menuList) { + var item = menuList[key]; + if (item.href === href) { + menu = item; + break; + } + if (item.child) { + newMenu = miniTab.searchMenu(href, item.child); + if (newMenu) { + menu = newMenu; + break; + } + } + } + return menu; + }, + + /** + * 监听 + * @param options + */ + listen: function (options) { + options = options || {}; + options.maxTabNum = options.maxTabNum || 20; + + /** + * 打开新窗口 + */ + $('body').on('click', '[layuimini-href]', function () { + var loading = layer.load(0, {shade: false, time: 2 * 1000}); + var tabId = $(this).attr('layuimini-href'), + href = $(this).attr('layuimini-href'), + title = $(this).text(), + target = $(this).attr('target'); + + var el = $("[layuimini-href='" + href + "']", ".layuimini-menu-left"); + layer.close(window.openTips); + if (el.length) { + $(el).closest(".layui-nav-tree").find(".layui-this").removeClass("layui-this"); + $(el).parent().addClass("layui-this"); + } + + if (target === '_blank') { + layer.close(loading); + window.open(href, "_blank"); + return false; + } + + if (tabId === null || tabId === undefined) tabId = new Date().getTime(); + var checkTab = miniTab.check(tabId); + if (!checkTab) { + miniTab.create({ + tabId: tabId, + href: href, + title: title, + isIframe: false, + maxTabNum: options.maxTabNum, + }); + } + element.tabChange('layuiminiTab', tabId); + layer.close(loading); + }); + + /** + * 在iframe子菜单上打开新窗口 + */ + $('body').on('click', '[layuimini-content-href]', function () { + var loading = parent.layer.load(0, {shade: false, time: 2 * 1000}); + var tabId = $(this).attr('layuimini-content-href'), + href = $(this).attr('layuimini-content-href'), + title = $(this).attr('data-title'), + target = $(this).attr('target'); + if (target === '_blank') { + parent.layer.close(loading); + window.open(href, "_blank"); + return false; + } + if (tabId === null || tabId === undefined) tabId = new Date().getTime(); + var checkTab = miniTab.check(tabId, true); + if (!checkTab) { + miniTab.create({ + tabId: tabId, + href: href, + title: title, + isIframe: true, + maxTabNum: options.maxTabNum, + }); + } + parent.layui.element.tabChange('layuiminiTab', tabId); + parent.layer.close(loading); + }); + + /** + * 关闭选项卡 + **/ + $('body').on('click', '.layuimini-tab .layui-tab-title .layui-tab-close', function () { + var loading = layer.load(0, {shade: false, time: 2 * 1000}); + var $parent = $(this).parent(); + var tabId = $parent.attr('lay-id'); + if (tabId !== undefined || tabId !== null) { + miniTab.delete(tabId); + } + layer.close(loading); + }); + + /** + * 选项卡操作 + */ + $('body').on('click', '[layuimini-tab-close]', function () { + var loading = layer.load(0, {shade: false, time: 2 * 1000}); + var closeType = $(this).attr('layuimini-tab-close'); + $(".layuimini-tab .layui-tab-title li").each(function () { + var tabId = $(this).attr('lay-id'); + var id = $(this).attr('id'); + var isCurrent = $(this).hasClass('layui-this'); + if (id !== 'layuiminiHomeTabId') { + if (closeType === 'all') { + miniTab.delete(tabId); + } else { + if (closeType === 'current' && isCurrent) { + miniTab.delete(tabId); + } else if (closeType === 'other' && !isCurrent) { + miniTab.delete(tabId); + } + } + } + }); + layer.close(loading); + }); + + /** + * 禁用网页右键 + */ + $(".layuimini-tab .layui-tab-title").unbind("mousedown").bind("contextmenu", function (e) { + e.preventDefault(); + return false; + }); + + /** + * 注册鼠标右键 + */ + $('body').on('mousedown', '.layuimini-tab .layui-tab-title li', function (e) { + var left = $(this).offset().left - $('.layuimini-tab ').offset().left + ($(this).width() / 2), + tabId = $(this).attr('lay-id'); + if (e.which === 3) { + miniTab.openTabRignMenu(tabId, left); + } + }); + + /** + * 关闭tab右键菜单 + */ + $('body').on('click', '.layui-body,.layui-header,.layuimini-menu-left,.layuimini-tab-make', function () { + miniTab.closeTabRignMenu(); + }); + + /** + * tab右键选项卡操作 + */ + $('body').on('click', '[layuimini-tab-menu-close]', function () { + var loading = layer.load(0, {shade: false, time: 2 * 1000}); + var closeType = $(this).attr('layuimini-tab-menu-close'), + currentTabId = $('.layuimini-tab-mousedown').attr('data-tab-id'); + $(".layuimini-tab .layui-tab-title li").each(function () { + var tabId = $(this).attr('lay-id'); + var id = $(this).attr('id'); + if (id !== 'layuiminiHomeTabId') { + if (closeType === 'all') { + miniTab.delete(tabId); + } else { + if (closeType === 'current' && currentTabId === tabId) { + miniTab.delete(tabId); + } else if (closeType === 'other' && currentTabId !== tabId) { + miniTab.delete(tabId); + } + } + } + }); + miniTab.closeTabRignMenu(); + layer.close(loading); + }); + }, + + /** + * 监听tab切换 + * @param options + */ + listenSwitch: function (options) { + options.filter = options.filter || null; + options.multiModule = options.multiModule || false; + options.urlHashLocation = options.urlHashLocation || false; + options.listenSwichCallback = options.listenSwichCallback || function () { + + }; + element.on('tab(' + options.filter + ')', function (data) { + var tabId = $(this).attr('lay-id'); + if (options.urlHashLocation) { + location.hash = '/' + tabId; + } + if (typeof options.listenSwichCallback === 'function') { + options.listenSwichCallback(); + } + // 判断是否为新增窗口 + if ($('.layuimini-menu-left').attr('layuimini-tab-tag') === 'add') { + $('.layuimini-menu-left').attr('layuimini-tab-tag', 'no') + } else { + $("[layuimini-href]").parent().removeClass('layui-this'); + if (options.multiModule) { + miniTab.listenSwitchMultiModule(tabId); + } else { + miniTab.listenSwitchSingleModule(tabId); + } + } + miniTab.rollPosition(); + }); + }, + + /** + * 监听hash变化 + * @param options + * @returns {boolean} + */ + listenHash: function (options) { + options.urlHashLocation = options.urlHashLocation || false; + options.maxTabNum = options.maxTabNum || 20; + options.homeInfo = options.homeInfo || {}; + options.menuList = options.menuList || []; + if (!options.urlHashLocation) return false; + var tabId = location.hash.replace(/^#\//, ''); + if (tabId === null || tabId === undefined || tabId ==='') return false; + + // 判断是否为首页 + if(tabId ===options.homeInfo.href) return false; + + // 判断是否为右侧菜单 + var menu = miniTab.searchMenu(tabId, options.menuList); + if (menu !== undefined) { + miniTab.create({ + tabId: tabId, + href: tabId, + title: menu.title, + isIframe: false, + maxTabNum: options.maxTabNum, + }); + $('.layuimini-menu-left').attr('layuimini-tab-tag', 'no'); + element.tabChange('layuiminiTab', tabId); + return false; + } + + // 判断是否为快捷菜单 + var isSearchMenu = false; + $("[layuimini-content-href]").each(function () { + if ($(this).attr("layuimini-content-href") === tabId) { + var title = $(this).attr("data-title"); + miniTab.create({ + tabId: tabId, + href: tabId, + title: title, + isIframe: false, + maxTabNum: options.maxTabNum, + }); + $('.layuimini-menu-left').attr('layuimini-tab-tag', 'no'); + element.tabChange('layuiminiTab', tabId); + isSearchMenu = true; + return false; + } + }); + if (isSearchMenu) return false; + + // 既不是右侧菜单、快捷菜单,就直接打开 + var title = sessionStorage.getItem('layuiminimenu_' + tabId) === null ? tabId : sessionStorage.getItem('layuiminimenu_' + tabId); + miniTab.create({ + tabId: tabId, + href: tabId, + title: title, + isIframe: false, + maxTabNum: options.maxTabNum, + }); + element.tabChange('layuiminiTab', tabId); + return false; + }, + + /** + * 监听滚动 + */ + listenRoll: function () { + $(".layuimini-tab-roll-left").click(function () { + miniTab.rollClick("left"); + }); + $(".layuimini-tab-roll-right").click(function () { + miniTab.rollClick("right"); + }); + }, + + /** + * 单模块切换 + * @param tabId + */ + listenSwitchSingleModule: function (tabId) { + $("[layuimini-href]").each(function () { + if ($(this).attr("layuimini-href") === tabId) { + // 自动展开菜单栏 + var addMenuClass = function ($element, type) { + if (type === 1) { + $element.addClass('layui-this'); + if ($element.hasClass('layui-nav-item') && $element.hasClass('layui-this')) { + $(".layuimini-header-menu li").attr('class', 'layui-nav-item'); + } else { + addMenuClass($element.parent().parent(), 2); + } + } else { + $element.addClass('layui-nav-itemed'); + if ($element.hasClass('layui-nav-item') && $element.hasClass('layui-nav-itemed')) { + $(".layuimini-header-menu li").attr('class', 'layui-nav-item'); + } else { + addMenuClass($element.parent().parent(), 2); + } + } + }; + addMenuClass($(this).parent(), 1); + return false; + } + }); + }, + + /** + * 多模块切换 + * @param tabId + */ + listenSwitchMultiModule: function (tabId) { + $("[layuimini-href]").each(function () { + if ($(this).attr("layuimini-href") === tabId) { + + // 自动展开菜单栏 + var addMenuClass = function ($element, type) { + if (type === 1) { + $element.addClass('layui-this'); + if ($element.hasClass('layui-nav-item') && $element.hasClass('layui-this')) { + var moduleId = $element.parent().attr('id'); + $(".layuimini-header-menu li").attr('class', 'layui-nav-item'); + $("#" + moduleId + "HeaderId").addClass("layui-this"); + $(".layuimini-menu-left .layui-nav.layui-nav-tree").attr('class', 'layui-nav layui-nav-tree layui-hide'); + $("#" + moduleId).attr('class', 'layui-nav layui-nav-tree layui-this'); + } else { + addMenuClass($element.parent().parent(), 2); + } + } else { + $element.addClass('layui-nav-itemed'); + if ($element.hasClass('layui-nav-item') && $element.hasClass('layui-nav-itemed')) { + var moduleId = $element.parent().attr('id'); + $(".layuimini-header-menu li").attr('class', 'layui-nav-item'); + $("#" + moduleId + "HeaderId").addClass("layui-this"); + $(".layuimini-menu-left .layui-nav.layui-nav-tree").attr('class', 'layui-nav layui-nav-tree layui-hide'); + $("#" + moduleId).attr('class', 'layui-nav layui-nav-tree layui-this'); + } else { + addMenuClass($element.parent().parent(), 2); + } + } + }; + addMenuClass($(this).parent(), 1); + return false; + } + }); + }, + + /** + * 自动定位 + */ + rollPosition: function () { + var $tabTitle = $('.layuimini-tab .layui-tab-title'); + var autoLeft = 0; + $tabTitle.children("li").each(function () { + if ($(this).hasClass('layui-this')) { + return false; + } else { + autoLeft += $(this).outerWidth(); + } + }); + $tabTitle.animate({ + scrollLeft: autoLeft - $tabTitle.width() / 3 + }, 200); + }, + + /** + * 点击滚动 + * @param direction + */ + rollClick: function (direction) { + var $tabTitle = $('.layuimini-tab .layui-tab-title'); + var left = $tabTitle.scrollLeft(); + if ('left' === direction) { + $tabTitle.animate({ + scrollLeft: left - 450 + }, 200); + } else { + $tabTitle.animate({ + scrollLeft: left + 450 + }, 200); + } + } + + }; + + exports("miniTab", miniTab); +}); diff --git a/ss-admin/src/main/resources/static/js/lay-module/layuimini/miniTheme.js b/ss-admin/src/main/resources/static/js/lay-module/layuimini/miniTheme.js new file mode 100644 index 0000000..6c19e6b --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/layuimini/miniTheme.js @@ -0,0 +1,475 @@ +/** + * date:2020/02/28 + * author:Mr.Chung + * version:2.0 + * description:layuimini tab框架扩展 + */ +layui.define(["jquery", "layer"], function (exports) { + var $ = layui.$, + layer = layui.layer; + + var miniTheme = { + + /** + * 主题配置项 + * @param bgcolorId + * @returns {{headerLogo, menuLeftHover, headerRight, menuLeft, headerRightThis, menuLeftThis}|*|*[]} + */ + config: function (bgcolorId) { + var bgColorConfig = [ + { + headerRightBg: '#ffffff', //头部右侧背景色 + headerRightBgThis: '#e4e4e4', //头部右侧选中背景色, + headerRightColor: 'rgba(107, 107, 107, 0.7)', //头部右侧字体颜色, + headerRightChildColor: 'rgba(107, 107, 107, 0.7)', //头部右侧下拉字体颜色, + headerRightColorThis: '#565656', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(160, 160, 160, 0.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#034f86', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#565656', //头部缩放按钮样式, + headerLogoBg: '#ffffff', //logo背景颜色, + headerLogoColor: 'rgb(191, 187, 187)', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#ffffff', //左侧菜单背景, + leftMenuBgThis: '#1E9FFF', //左侧菜单选中背景, + leftMenuChildBg: '#ffffff', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(40, 31, 31)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#c2bb34', //tab选项卡选中颜色, + }, + { + headerRightBg: '#23262e', //头部右侧背景色 + headerRightBgThis: '#0c0c0c', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#1aa094', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#0c0c0c', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#23262e', //左侧菜单背景, + leftMenuBgThis: '#737373', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#23262e', //tab选项卡选中颜色, + }, + { + headerRightBg: '#ffa4d1', //头部右侧背景色 + headerRightBgThis: '#bf7b9d', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#ffa4d1', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#e694bd', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#1f1f1f', //左侧菜单背景, + leftMenuBgThis: '#737373', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#ffa4d1', //tab选项卡选中颜色, + }, + { + headerRightBg: '#1aa094', //头部右侧背景色 + headerRightBgThis: '#197971', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#1aa094', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#0c0c0c', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#23262e', //左侧菜单背景, + leftMenuBgThis: '#1aa094', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#1aa094', //tab选项卡选中颜色, + }, + { + headerRightBg: '#1e9fff', //头部右侧背景色 + headerRightBgThis: '#0069b7', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#1e9fff', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#0c0c0c', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#1f1f1f', //左侧菜单背景, + leftMenuBgThis: '#1e9fff', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#1e9fff', //tab选项卡选中颜色, + }, + { + headerRightBg: '#ffb800', //头部右侧背景色 + headerRightBgThis: '#d09600', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#d09600', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#243346', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#2f4056', //左侧菜单背景, + leftMenuBgThis: '#8593a7', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#ffb800', //tab选项卡选中颜色, + }, + { + headerRightBg: '#e82121', //头部右侧背景色 + headerRightBgThis: '#ae1919', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#ae1919', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#0c0c0c', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#1f1f1f', //左侧菜单背景, + leftMenuBgThis: '#3b3f4b', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#e82121', //tab选项卡选中颜色, + }, + { + headerRightBg: '#963885', //头部右侧背景色 + headerRightBgThis: '#772c6a', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#772c6a', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#243346', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#2f4056', //左侧菜单背景, + leftMenuBgThis: '#586473', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#963885', //tab选项卡选中颜色, + }, + { + headerRightBg: '#2D8CF0', //头部右侧背景色 + headerRightBgThis: '#0069b7', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#0069b7', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#0069b7', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#1f1f1f', //左侧菜单背景, + leftMenuBgThis: '#2D8CF0', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#2d8cf0', //tab选项卡选中颜色, + }, + { + headerRightBg: '#ffb800', //头部右侧背景色 + headerRightBgThis: '#d09600', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#d09600', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#d09600', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#2f4056', //左侧菜单背景, + leftMenuBgThis: '#3b3f4b', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#ffb800', //tab选项卡选中颜色, + }, + { + headerRightBg: '#e82121', //头部右侧背景色 + headerRightBgThis: '#ae1919', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#ae1919', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#d91f1f', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#1f1f1f', //左侧菜单背景, + leftMenuBgThis: '#3b3f4b', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#e82121', //tab选项卡选中颜色, + }, + { + headerRightBg: '#963885', //头部右侧背景色 + headerRightBgThis: '#772c6a', //头部右侧选中背景色, + headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色, + headerRightChildColor: '#676767', //头部右侧下拉字体颜色, + headerRightColorThis: '#ffffff', //头部右侧鼠标选中, + headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色, + headerRightNavMoreBg: '#772c6a', //头部右侧更多下拉列表选中背景色, + headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色, + headerRightToolColor: '#bbe3df', //头部缩放按钮样式, + headerLogoBg: '#772c6a', //logo背景颜色, + headerLogoColor: '#ffffff', //logo字体颜色, + leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式, + leftMenuBg: '#2f4056', //左侧菜单背景, + leftMenuBgThis: '#626f7f', //左侧菜单选中背景, + leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景, + leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色, + leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色, + tabActiveColor: '#963885', //tab选项卡选中颜色, + } + ]; + if (bgcolorId === undefined) { + return bgColorConfig; + } else { + return bgColorConfig[bgcolorId]; + } + }, + + /** + * 初始化 + * @param options + */ + render: function (options) { + options.bgColorDefault = options.bgColorDefault || false; + options.listen = options.listen || false; + var bgcolorId = sessionStorage.getItem('layuiminiBgcolorId'); + if (bgcolorId === null || bgcolorId === undefined || bgcolorId === '') { + bgcolorId = options.bgColorDefault; + } + miniTheme.buildThemeCss(bgcolorId); + if (options.listen) miniTheme.listen(options); + }, + + /** + * 构建主题样式 + * @param bgcolorId + * @returns {boolean} + */ + buildThemeCss: function (bgcolorId) { + if (!bgcolorId) { + return false; + } + var bgcolorData = miniTheme.config(bgcolorId); + var styleHtml = '/*头部右侧背景色 headerRightBg */\n' + + '.layui-layout-admin .layui-header {\n' + + ' background-color: ' + bgcolorData.headerRightBg + ' !important;\n' + + '}\n' + + '\n' + + '/*头部右侧选中背景色 headerRightBgThis */\n' + + '.layui-layout-admin .layui-header .layuimini-header-content > ul > .layui-nav-item.layui-this, .layuimini-tool i:hover {\n' + + ' background-color: ' + bgcolorData.headerRightBgThis + ' !important;\n' + + '}\n' + + '\n' + + '/*头部右侧字体颜色 headerRightColor */\n' + + '.layui-layout-admin .layui-header .layui-nav .layui-nav-item a {\n' + + ' color: ' + bgcolorData.headerRightColor + ';\n' + + '}\n' + + '/**头部右侧下拉字体颜色 headerRightChildColor */\n' + + '.layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child a {\n' + + ' color: ' + bgcolorData.headerRightChildColor + '!important;\n' + + '}\n'+ + '\n' + + '/*头部右侧鼠标选中 headerRightColorThis */\n' + + '.layui-header .layuimini-menu-header-pc.layui-nav .layui-nav-item a:hover, .layui-header .layuimini-header-menu.layuimini-pc-show.layui-nav .layui-this a {\n' + + ' color: ' + bgcolorData.headerRightColorThis + ' !important;\n' + + '}\n' + + '\n' + + '/*头部右侧更多下拉颜色 headerRightNavMore */\n' + + '.layui-header .layui-nav .layui-nav-more {\n' + + ' border-top-color: ' + bgcolorData.headerRightNavMore + ' !important;\n' + + '}\n' + + '\n' + + '/*头部右侧更多下拉颜色 headerRightNavMore */\n' + + '.layui-header .layui-nav .layui-nav-mored, .layui-header .layui-nav-itemed > a .layui-nav-more {\n' + + ' border-color: transparent transparent ' + bgcolorData.headerRightNavMore + ' !important;\n' + + '}\n' + + '\n' + + '/**头部右侧更多下拉配置色 headerRightNavMoreBg headerRightNavMoreColor */\n' + + '.layui-header .layui-nav .layui-nav-child dd.layui-this a, .layui-header .layui-nav-child dd.layui-this, .layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child .layui-this a {\n' + + ' background-color: ' + bgcolorData.headerRightNavMoreBg + ' !important;\n' + + ' color:' + bgcolorData.headerRightNavMoreColor + ' !important;\n' + + '}\n' + + '\n' + + '/*头部缩放按钮样式 headerRightToolColor */\n' + + '.layui-layout-admin .layui-header .layuimini-tool i {\n' + + ' color: ' + bgcolorData.headerRightToolColor + ';\n' + + '}\n' + + '\n' + + '/*logo背景颜色 headerLogoBg */\n' + + '.layui-layout-admin .layuimini-logo {\n' + + ' background-color: ' + bgcolorData.headerLogoBg + ' !important;\n' + + '}\n' + + '\n' + + '/*logo字体颜色 headerLogoColor */\n' + + '.layui-layout-admin .layuimini-logo h1 {\n' + + ' color: ' + bgcolorData.headerLogoColor + ';\n' + + '}\n' + + '\n' + + '/*左侧菜单更多下拉样式 leftMenuNavMore */\n' + + '.layuimini-menu-left .layui-nav .layui-nav-more,.layuimini-menu-left-zoom.layui-nav .layui-nav-more {\n' + + ' border-top-color: ' + bgcolorData.leftMenuNavMore + ';\n' + + '}\n' + + '\n' + + '/*左侧菜单更多下拉样式 leftMenuNavMore */\n' + + '.layuimini-menu-left .layui-nav .layui-nav-mored, .layuimini-menu-left .layui-nav-itemed > a .layui-nav-more, .layuimini-menu-left-zoom.layui-nav .layui-nav-mored, .layuimini-menu-left-zoom.layui-nav-itemed > a .layui-nav-more {\n' + + ' border-color: transparent transparent ' + bgcolorData.leftMenuNavMore + ' !important;\n' + + '}\n' + + '\n' + + '/*左侧菜单背景 leftMenuBg */\n' + + '.layui-side.layui-bg-black, .layui-side.layui-bg-black > .layuimini-menu-left > ul, .layuimini-menu-left-zoom > ul {\n' + + ' background-color: ' + bgcolorData.leftMenuBg + ' !important;\n' + + '}\n' + + '\n' + + '/*左侧菜单选中背景 leftMenuBgThis */\n' + + '.layuimini-menu-left .layui-nav-tree .layui-this, .layuimini-menu-left .layui-nav-tree .layui-this > a, .layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this, .layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this a, .layuimini-menu-left-zoom.layui-nav-tree .layui-this, .layuimini-menu-left-zoom.layui-nav-tree .layui-this > a, .layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this, .layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this a {\n' + + ' background-color: ' + bgcolorData.leftMenuBgThis + ' !important\n' + + '}\n' + + '\n' + + '/*左侧菜单子菜单背景 leftMenuChildBg */\n' + + '.layuimini-menu-left .layui-nav-itemed > .layui-nav-child{\n' + + ' background-color: ' + bgcolorData.leftMenuChildBg + ' !important;\n' + + '}\n' + + '\n' + + '/*左侧菜单字体颜色 leftMenuColor */\n' + + '.layuimini-menu-left .layui-nav .layui-nav-item a, .layuimini-menu-left-zoom.layui-nav .layui-nav-item a {\n' + + ' color: ' + bgcolorData.leftMenuColor + ' !important;\n' + + '}\n' + + '\n' + + '/*左侧菜单选中字体颜色 leftMenuColorThis */\n' + + '.layuimini-menu-left .layui-nav , .layuimini-menu-left .layui-nav .layui-this a, .layuimini-menu-left-zoom.layui-nav , .layuimini-menu-left-zoom.layui-nav .layui-this a {\n' + + ' color:' + bgcolorData.leftMenuColorThis + ' !important;\n' + + '}\n' + + '\n' + + '/**tab选项卡选中颜色 tabActiveColor */\n' + + '.layuimini-tab .layui-tab-title .layui-this .layuimini-tab-active {\n' + + ' background-color: ' + bgcolorData.tabActiveColor + ';\n' + + '}\n'; + + $('#layuimini-bg-color').html(styleHtml); + }, + + /** + * 构建主题选择html + * @param options + * @returns {string} + */ + buildBgColorHtml: function (options) { + options.bgColorDefault = options.bgColorDefault || 0; + var bgcolorId = parseInt(sessionStorage.getItem('layuiminiBgcolorId')); + if (isNaN(bgcolorId)) bgcolorId = options.bgColorDefault; + var bgColorConfig = miniTheme.config(); + var html = ''; + $.each(bgColorConfig, function (key, val) { + if (key === bgcolorId) { + html += '
  • \n'; + } else { + html += '
  • \n'; + } + html += '\n' + + '
    \n' + + '
    \n' + + '
    \n' + + '
  • '; + }); + return html; + }, + + /** + * 监听 + * @param options + */ + listen: function (options) { + $('body').on('click', '[data-bgcolor]', function () { + var loading = layer.load(0, {shade: false, time: 2 * 1000}); + var clientHeight = (document.documentElement.clientHeight) - 60; + var bgColorHtml = miniTheme.buildBgColorHtml(options); + var html = '
    \n' + + '
    \n' + + '配色方案\n' + + '
    \n' + + '
    \n' + + '
      \n' + bgColorHtml + '
    \n' + + '
    \n' + + '
    \n' + + ' 开发文档\n' + + ' 开源地址\n' + + ' 官方网站\n' + + '
    ' + + '
    '; + layer.open({ + type: 1, + title: false, + closeBtn: 0, + shade: 0.2, + anim: 2, + shadeClose: true, + id: 'layuiminiBgColor', + area: ['340px', clientHeight + 'px'], + offset: 'rb', + content: html, + success: function (index, layero) { + }, + end: function () { + $('.layuimini-select-bgcolor').removeClass('layui-this'); + } + }); + layer.close(loading); + }); + + $('body').on('click', '[data-select-bgcolor]', function () { + var bgcolorId = $(this).attr('data-select-bgcolor'); + $('.layuimini-color .color-content ul .layui-this').attr('class', ''); + $(this).attr('class', 'layui-this'); + sessionStorage.setItem('layuiminiBgcolorId', bgcolorId); + miniTheme.render({ + bgColorDefault: bgcolorId, + listen: false, + }); + }); + } + }; + + exports("miniTheme", miniTheme); + +}) +; diff --git a/ss-admin/src/main/resources/static/js/lay-module/layuimini/miniTongji.js b/ss-admin/src/main/resources/static/js/lay-module/layuimini/miniTongji.js new file mode 100644 index 0000000..f0ca101 --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/layuimini/miniTongji.js @@ -0,0 +1,40 @@ +/** + * date:2020/03/01 + * author:Mr.Chung + * version:2.0 + * description:layuimini 统计框架扩展 + */ +layui.define(["jquery"], function (exports) { + var $ = layui.$; + + var miniTongji = { + + /** + * 初始化 + * @param options + */ + render: function (options) { + options.specific = options.specific || false; + options.domains = options.domains || []; + var domain = window.location.hostname; + if (options.specific === false || (options.specific === true && options.domains.indexOf(domain) >=0)) { + miniTongji.listen(); + } + }, + + /** + * 监听统计代码 + */ + listen: function () { + var _hmt = _hmt || []; + (function () { + var hm = document.createElement("script"); + hm.src = "https://hm.baidu.com/hm.js?d97abf6d61c21d773f97835defbdef4e"; + var s = document.getElementsByTagName("script")[0]; + s.parentNode.insertBefore(hm, s); + })(); + } + }; + + exports("miniTongji", miniTongji); +}); \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/js/lay-module/step-lay/step.css b/ss-admin/src/main/resources/static/js/lay-module/step-lay/step.css new file mode 100644 index 0000000..cc5e2ce --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/step-lay/step.css @@ -0,0 +1,79 @@ +.lay-step { + font-size: 0; + width: 400px; + margin: 0 auto; + max-width: 100%; + padding-left: 200px; +} + +.step-item { + display: inline-block; + line-height: 26px; + position: relative; + font-size: 14px; +} + +.step-item-tail { + width: 100%; + padding: 0 10px; + position: absolute; + left: 0; + top: 13px; +} + +.step-item-tail i { + display: inline-block; + width: 100%; + height: 1px; + vertical-align: top; + background: #c2c2c2; + position: relative; +} + +.step-item-tail .step-item-tail-done { + background: #009688; +} + +.step-item-head { + position: relative; + display: inline-block; + height: 26px; + width: 26px; + text-align: center; + vertical-align: top; + color: #009688; + border: 1px solid #009688; + border-radius: 50%; + background: #ffffff; +} + +.step-item-head.step-item-head-active { + background: #009688; + color: #ffffff; +} + +.step-item-main { + display: block; + position: relative; + margin-left: -50%; + margin-right: 50%; + padding-left: 26px; + text-align: center; +} + +.step-item-main-title { + font-weight: bolder; + color: #555555; +} + +.step-item-main-desc { + color: #aaaaaa; +} + +.lay-step + [carousel-item]:before { + display: none; +} + +.lay-step + [carousel-item] > * { + background-color: transparent; +} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/js/lay-module/step-lay/step.js b/ss-admin/src/main/resources/static/js/lay-module/step-lay/step.js new file mode 100644 index 0000000..baa015b --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/step-lay/step.js @@ -0,0 +1,101 @@ +layui.define(['layer', 'carousel'], function (exports) { + var $ = layui.jquery; + var layer = layui.layer; + var carousel = layui.carousel; + + // 添加步骤条dom节点 + var renderDom = function (elem, stepItems, postion) { + var stepDiv = '
    '; + for (var i = 0; i < stepItems.length; i++) { + stepDiv += '
    '; + // 线 + if (i < (stepItems.length - 1)) { + if (i < postion) { + stepDiv += '
    '; + } else { + stepDiv += '
    '; + } + } + + // 数字 + var number = stepItems[i].number; + if (!number) { + number = i + 1; + } + if (i == postion) { + stepDiv += '
    ' + number + '
    '; + } else if (i < postion) { + stepDiv += '
    '; + } else { + stepDiv += '
    ' + number + '
    '; + } + + // 标题和描述 + var title = stepItems[i].title; + var desc = stepItems[i].desc; + if (title || desc) { + stepDiv += '
    '; + if (title) { + stepDiv += '
    ' + title + '
    '; + } + if (desc) { + stepDiv += '
    ' + desc + '
    '; + } + stepDiv += '
    '; + } + stepDiv += '
    '; + } + stepDiv += '
    '; + + $(elem).prepend(stepDiv); + + // 计算每一个条目的宽度 + var bfb = 100 / stepItems.length; + $('.step-item').css('width', bfb + '%'); + }; + + var step = { + // 渲染步骤条 + render: function (param) { + param.indicator = 'none'; // 不显示指示器 + param.arrow = 'always'; // 始终显示箭头 + param.autoplay = false; // 关闭自动播放 + if (!param.stepWidth) { + param.stepWidth = '400px'; + } + + // 渲染轮播图 + carousel.render(param); + + // 渲染步骤条 + var stepItems = param.stepItems; + renderDom(param.elem, stepItems, 0); + $('.lay-step').css('width', param.stepWidth); + + //监听轮播切换事件 + carousel.on('change(' + param.filter + ')', function (obj) { + $(param.elem).find('.lay-step').remove(); + renderDom(param.elem, stepItems, obj.index); + $('.lay-step').css('width', param.stepWidth); + }); + + // 隐藏左右箭头按钮 + $(param.elem).find('.layui-carousel-arrow').css('display', 'none'); + + // 去掉轮播图的背景颜色 + $(param.elem).css('background-color', 'transparent'); + }, + // 下一步 + next: function (elem) { + $(elem).find('.layui-carousel-arrow[lay-type=add]').trigger('click'); + }, + // 上一步 + pre: function (elem) { + $(elem).find('.layui-carousel-arrow[lay-type=sub]').trigger('click'); + } + }; + + layui.link(layui.cache.base + 'step-lay/step.css'); + + exports('step', step); +}); diff --git a/ss-admin/src/main/resources/static/js/lay-module/tableSelect/tableSelect.js b/ss-admin/src/main/resources/static/js/lay-module/tableSelect/tableSelect.js new file mode 100644 index 0000000..84acc3d --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/tableSelect/tableSelect.js @@ -0,0 +1,272 @@ +layui.define(['table', 'jquery', 'form'], function (exports) { + "use strict"; + + var MOD_NAME = 'tableSelect', + $ = layui.jquery, + table = layui.table, + form = layui.form; + var tableSelect = function () { + this.v = '1.1.0'; + }; + + /** + * 初始化表格选择器 + */ + tableSelect.prototype.render = function (opt) { + var elem = $(opt.elem); + var tableDone = opt.table.done || function(){}; + + //默认设置 + opt.searchKey = opt.searchKey || 'keyword'; + opt.searchPlaceholder = opt.searchPlaceholder || '关键词搜索'; + opt.checkedKey = opt.checkedKey; + opt.table.page = opt.table.page || true; + opt.table.height = opt.height || 315; + + //最小宽度 + opt.width = opt.width || '530'; + + //多搜索条件 + opt.searchType = opt.searchType || 'one'; + opt.searchList = opt.searchList || [{key: opt.searchKey, placeholder: opt.searchPlaceholder}]; + + elem.off('click').on('click', function(e) { + e.stopPropagation(); + + if($('div.tableSelect').length >= 1){ + return false; + } + + var t = elem.offset().top + elem.outerHeight()+"px"; + var l = elem.offset().left +"px"; + var tableName = "tableSelect_table_" + new Date().getTime(); + var tableBox = '
    '; + tableBox += '
    '; + tableBox += '
    '; + + //判断是否多搜索条件 + if(opt.searchType == 'more'){ + $.each(opt.searchList, function (index, item) { + tableBox += ''; + }); + }else{ + tableBox += ''; + } + + tableBox += ''; + tableBox += ''; + tableBox += ''; + tableBox += '
    '; + tableBox += '
    '; + tableBox += ''; + tableBox = $(tableBox); + $('body').append(tableBox); + + //数据缓存 + var checkedData = []; + + //渲染TABLE + opt.table.elem = "#"+tableName; + opt.table.id = tableName; + opt.table.done = function(res, curr, count){ + defaultChecked(res, curr, count); + setChecked(res, curr, count); + tableDone(res, curr, count); + }; + var tableSelect_table = table.render(opt.table); + + //分页选中保存数组 + table.on('radio('+tableName+')', function(obj){ + if(opt.checkedKey){ + checkedData = table.checkStatus(tableName).data + } + updataButton(table.checkStatus(tableName).data.length) + }) + table.on('checkbox('+tableName+')', function(obj){ + if(opt.checkedKey){ + if(obj.checked){ + for (var i=0;i $(window).height(); + var overWidth = (elem.offset().left + tableBox.outerWidth()) > $(window).width(); + overHeight && tableBox.css({'top':'auto','bottom':'0px'}); + overWidth && tableBox.css({'left':'auto','right':'5px'}) + + //关键词搜索 + form.on('submit(tableSelect_btn_search)', function(data){ + tableSelect_table.reload({ + where: data.field, + page: { + curr: 1 + } + }); + return false; + }); + + //双击行选中 + table.on('rowDouble('+tableName+')', function(obj){ + var checkStatus = {data:[obj.data]}; + selectDone(checkStatus); + }) + + //按钮选中 + tableBox.find('.tableSelect_btn_select').on('click', function() { + var checkStatus = table.checkStatus(tableName); + if(checkedData.length > 1){ + checkStatus.data = checkedData; + } + selectDone(checkStatus); + }) + + //写值回调和关闭 + function selectDone (checkStatus){ + if(opt.checkedKey){ + var selected = []; + for(var i=0;i i { + color: #999; + font-size: 30px; +} + +.ew-tree-table .ew-tree-table-loading.ew-loading-float { + position: absolute; + top: 0; + left: 0; + right: 0; +} + +/** 空数据 */ +.ew-tree-table .ew-tree-table-empty { + color: #666; + font-size: 14px; + padding: 18px 0; + text-align: center; + display: none; +} + +/** 单元格 */ +.ew-tree-table-cell.ew-tree-tips-open { + position: absolute; + top: 0; + left: 0; + padding: 0; + z-index: 19891015; + background-color: #fff; + box-shadow: 3px 3px 8px rgba(0, 0, 0, .15); +} + +thead .ew-tree-table-cell.ew-tree-tips-open { + background-color: #f2f2f2; +} + +.ew-tree-table-cell.ew-tree-tips-open.ew-show-left { + right: 0; + left: auto; + box-shadow: -3px 3px 8px rgba(0, 0, 0, .15); +} + +.ew-tree-table-cell.ew-tree-tips-open.ew-show-bottom { + bottom: 0; + top: auto; + box-shadow: 3px -3px 8px rgba(0, 0, 0, .15); +} + +.ew-tree-table-cell.ew-tree-tips-open.ew-show-left.ew-show-bottom { + box-shadow: -3px -3px 8px rgba(0, 0, 0, .15); +} + +.ew-tree-table-cell > .ew-tree-tips-c { + position: absolute; + right: -6px; + top: -3px; + width: 22px; + height: 22px; + line-height: 22px; + font-size: 16px; + color: #fff; + background-color: #666; + border-radius: 50%; + text-align: center; + cursor: pointer; + display: none; +} + +table tr:first-child .ew-tree-table-cell > .ew-tree-tips-c { + top: 0; +} + +.ew-tree-table-cell.ew-tree-tips-open > .ew-tree-tips-c { + display: block; +} + +.ew-tree-table-cell.ew-tree-tips-open.ew-show-left > .ew-tree-tips-c { + left: -6px; + right: auto; +} + +.ew-tree-table-cell > .ew-tree-table-cell-content { + padding: 5px 15px; + line-height: 28px; +} + +[lay-size="lg"] .ew-tree-table-cell > .ew-tree-table-cell-content { + line-height: 40px; +} + +[lay-size="sm"] .ew-tree-table-cell > .ew-tree-table-cell-content { + padding: 1px 15px; +} + +.ew-tree-table-cell.single-line > .ew-tree-table-cell-content { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.ew-tree-table-cell.ew-tree-tips-open > .ew-tree-table-cell-content { + overflow: auto; + padding: 9px 15px; + height: auto; + min-height: 100%; + max-height: 110px; + line-height: inherit; + max-width: 260px; + width: 200px; + width: max-content; + width: -moz-max-content; + box-sizing: border-box; + white-space: normal; +} + +.ew-tree-table-cell > .layui-table-grid-down { + box-sizing: border-box; +} + +/** 图标列 */ +.ew-tree-table .ew-tree-pack { + cursor: pointer; + line-height: 16px; +} + +.ew-tree-table .ew-tree-pack > .layui-icon, .ew-tree-table .ew-tree-pack > .ew-tree-icon { + margin-right: 5px; +} + +.ew-tree-table .ew-tree-pack > * { + vertical-align: middle; +} + +/* 缩进 */ +.ew-tree-table .ew-tree-table-indent { + margin-right: 5px; + padding-left: 16px; +} + +/* 箭头 */ +.ew-tree-table .ew-tree-table-arrow:before { + content: "\e623"; +} + +.ew-tree-table .ew-tree-table-open .ew-tree-table-arrow:before { + content: "\e625"; +} + +.ew-tree-table .ew-tree-table-arrow.arrow2 { + font-size: 12px; + font-weight: 600; + line-height: 16px; + height: 16px; + width: 16px; + display: inline-block; + text-align: center; + color: #888; +} + +.ew-tree-table .ew-tree-table-arrow.arrow2:before { + content: "\e602"; +} + +.ew-tree-table .ew-tree-table-open .ew-tree-table-arrow.arrow2:before { + content: "\e61a"; +} + +.ew-tree-table-arrow.ew-tree-table-arrow-hide { + visibility: hidden; +} + +/* 箭头变加载中状态 */ +.ew-tree-table .ew-tree-table-loading > td .ew-tree-table-arrow:before { + content: "\e63d" !important; +} + +.ew-tree-table .ew-tree-table-loading > td .ew-tree-table-arrow { + margin-right: 0; +} + +.ew-tree-table .ew-tree-table-loading > td .ew-tree-table-arrow + * { + margin-left: 5px; +} + +.ew-tree-table .ew-tree-table-loading * { + pointer-events: none !important; +} + +/** 折叠行 */ +.ew-tree-table .ew-tree-tb-hide { + display: none; +} + +/** 特殊列调整 */ +.ew-tree-table td[data-type="numbers"] > .ew-tree-table-cell, +.ew-tree-table th[data-type="numbers"] > .ew-tree-table-cell, +.ew-tree-table td[data-type="checkbox"] > .ew-tree-table-cell, +.ew-tree-table th[data-type="checkbox"] > .ew-tree-table-cell, +.ew-tree-table td[data-type="radio"] > .ew-tree-table-cell, +.ew-tree-table th[data-type="radio"] > .ew-tree-table-cell, +.ew-tree-table td[data-type="space"] > .ew-tree-table-cell, +.ew-tree-table th[data-type="space"] > .ew-tree-table-cell { + padding-left: 0; + padding-right: 0; +} + +/* 单元格内表单元素样式调整 */ +.ew-tree-table .layui-form-switch, +.ew-tree-table .layui-form-radio { + margin: 0; +} + +/* checkbox列调整 */ +.ew-tree-table-checkbox + .layui-form-checkbox { + padding: 0; +} + +.ew-tree-table-checkbox + .layui-form-checkbox > .layui-icon { + font-weight: 600; + color: transparent; + transition: background-color .1s linear; + -webkit-transition: background-color .1s linear; +} + +.ew-tree-table-checkbox + .layui-form-checkbox.layui-form-checked > .layui-icon { + color: #fff; +} + +/* checkbox半选状态 */ +.ew-form-indeterminate + .layui-form-checkbox .layui-icon:before { + content: ""; + width: 10px; + height: 2px; + background-color: #f1f1f1; + position: absolute; + top: 50%; + left: 50%; + margin: -1px 0 0 -5px; +} + +/* radio列调整 */ +.ew-tree-table-radio + .layui-form-radio { + padding: 0; + height: 20px; + line-height: 20px; +} + +.ew-tree-table-radio + .layui-form-radio > i { + margin: 0; + height: 20px; + font-size: 20px; + line-height: 20px; +} + +/** 单元格编辑 */ +.ew-tree-table .layui-table td[data-edit] { + cursor: text; +} + +.ew-tree-table .ew-tree-table-edit { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + border-radius: 0; + box-shadow: 1px 1px 20px rgba(0, 0, 0, .15); +} + +.ew-tree-table .ew-tree-table-edit:focus { + border-color: #5FB878 !important; +} + +.ew-tree-table .ew-tree-table-edit.layui-form-danger { + border-color: #FF5722 !important; +} + +/** 搜索数据隐藏行 */ +.ew-tree-table tr.ew-tree-table-filter-hide { + display: none !important; +} + +/** 头部工具栏 */ +.ew-tree-table .ew-tree-table-tool { + min-height: 50px; + line-height: 30px; + padding: 10px 15px; + box-sizing: border-box; + background-color: #f2f2f2; + border-bottom: 1px solid #e6e6e6; +} + +.ew-tree-table .ew-tree-table-tool .ew-tree-table-tool-right { + float: right; +} + +.ew-tree-table .ew-tree-table-tool .ew-tree-table-tool-item { + position: relative; + color: #333; + width: 26px; + height: 26px; + line-height: 26px; + text-align: center; + margin-left: 10px; + display: inline-block; + border: 1px solid #ccc; + box-sizing: border-box; + vertical-align: middle; + -webkit-transition: .3s all; + transition: .3s all; + cursor: pointer; +} + +.ew-tree-table .ew-tree-table-tool .ew-tree-table-tool-item:first-child { + margin-left: 0; +} + +.ew-tree-table .ew-tree-table-tool .ew-tree-table-tool-item:hover { + border-color: #999; +} + +.ew-tree-table .ew-tree-table-tool-right .layui-table-tool-panel { + left: auto; + right: -1px; + z-index: 9999; +} + +/* 列宽拖拽调整 */ +.ew-tree-table .ew-tb-resize { + position: absolute; + right: 0; + top: 0; + bottom: 0; + width: 10px; + cursor: col-resize; +} + +.ew-tree-table-resizing { + cursor: col-resize; + -ms-user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; +} + +/* 辅助样式 */ +.ew-tree-table .layui-form-switch { + margin: 0; +} + +.ew-tree-table .pd-tb-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.ew-tree-table .break-all { + word-break: break-all !important; +} + +/** 扩展图标 */ +.ew-tree-table .ew-tree-icon-folder:after, .ew-tree-table .ew-tree-icon-file:after { + content: ""; + padding: 2px 10px; + -webkit-background-size: cover; + -moz-background-size: cover; + -o-background-size: cover; + background-size: cover; + background-repeat: no-repeat; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAE6UlEQVR4Xu2ZPYhcVRiGny9hC0FsTEBCGkFTWIQE/IlpgmKpWAiLyR0XLbYTxEKxkCAEhRCxEOwsjJnJioKIYClWKgqiskIIaCoLYyASVJT87JGspN37LrOXvec777Tzzrnvz7Nn2dnAr6YbiKbTOzwGoHEIDIABaLyBxuP7BjAAjTfQeHzfAAag8QYaj+8bwAA03kDj8X0DGIDGG2g8/lw3QFlhD9fZN7oOF7gYT3NudL5GaGjTAJQP2c1VXgIOExyGkf4/oXCe4I3oeH+EvY/G0qYAKFOWCV4Hdo8mQb+RL7jBE7HE3/3S9hQyAGXGCeDVSiv6lqscief4t1L/g9mWAChTHiD4ZrTXvVbPu9GxrEnbUWkAzPgeOJCglsXo+ChBji2L0AtAmfEgrP/0Z3hdZoF7Y5HLGcJsRQYFgLeAF7fiYSM540x0LI3Ey7bb6AdgytcEh7bd6VYa2MGhOJrmVpurmX4AZlwCds31lPF9+AI32O8/DYUvccqUKwR3jG/DuR29Gd36F1pNv/pvgKwAFK5RuC+e4eeWCWgXgJurFz6LCY8bgA0aSPwr4P/UhVNc43ir3xK2fQPcAr/wO/AewU/Ar6xRqroVdvAnC6zGIlc369sAbLax8er/ofAJOzkVR9e/uZVeBkCqqTrRyeh4RXFtAJSWatQUno0Jp/usG4C+hup9/yJ72BuPcH2jCAag3oEV50vRccYAKFXl1LwdHS8YgJzj9qcqfBoTnjQA/VVlVXwXHfcbgKzz9uf6IToOGoD+orIqDEDWZcVcBkAsKqvMAGRdVsxlAMSissoMQNZlxVwGQCwqq8wAZF1WzGUAxKKyygxA1mXFXAZALCqrzABkXVbMZQDEorLKDEDWZcVcBkAsKqvMAGRdVsxlAMSissoMQNZlxVwGQCwqq8wAZF1WzGUAxKKyygxA1mXFXAZALCqrzABkXVbMZQDEorLKDEDWZcVcBkAsKqvMAGRdVsxlAMSissoMQNZlxVwGQCwqq8wAZF1WzGUAxKKyygxA1mXFXAZALCqrzABkXVbMZQDEorLKDEDWZcVcBkAsKqvMAGRdVsxlAMSissoMQNZlxVwGQCwqq8wAZF1WzGUAxKKyygxA1mXFXAZALCqrzABkXVbMZQDEorLKDEDWZcVcBkAsKqvMAGRdVsxlAMSissoMQNZlxVwGQCwqq8wAZF1WzGUAxKKyygxA1mXFXAZALCqrzABkXVbMZQDEorLKDEDWZcVcBkAsKqvMAGRdVsxlAMSissoMQNZlxVwGQCwqq8wAZF1WzLUFAMy4BOwSH2jZmBoorMaE/RtZij6/ZcoFgrv7dH5/lA38Eh33zAfAjM+BR0cZz6Y2bqDwY0w4MB8AU04SvOyuq2zg4+h4aj4AzvIwha+qjN+66cLzMeGduQC4+eEy4zywr/U+K8t/hQX2xiJ/zQ/ACgdZ40vgtspKaNducCyOsdJXQO9fAbcOKGc5whofENzVd6jf3/YGTkTHccWFDMD6r4LT3MlOloHHCB4CblceYs3gDfxB4TeCcxReiwmr6hM3BYB6qHX1NGAA6tlqEKcGYJBa6znUANSz1SBODcAgtdZzqAGoZ6tBnBqAQWqt51ADUM9Wgzg1AIPUWs+hBqCerQZxagAGqbWeQw1APVsN4tQADFJrPYcagHq2GsTpf+KxwJB5Cd5mAAAAAElFTkSuQmCC"); +} + +.ew-tree-table tr.ew-tree-table-open > td .ew-tree-icon-folder:after { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAKwElEQVR4Xu2df9AVVRnHP899gUxmYKhsCpJREEeMakSoiGGCbIxSizIJ7i5OksZkMIxQjlOQyOCQ5o/8RWmkMdz7wjDC5I+hcFSKxEENh4YsEwPJAbVQ8AeQL733NPcKyn3v7r17d8/uvfvus//ec57n+3yf7z179uw5zwp6ZZoByXT0GjwqgIyLQAWgAsg4AxkPX0cAFUDGGch4+DoCqAAyzkDGw9cRQAWQcQYyHr6OACqA5hkw63kfr3IyOQZTIte8BUs9OnibEi/isEcEY8lqpswEHgHMGgbSxTyEyRjGIC1MfM8UGQ4CfyLHWp7jbllEKVNZjBBsIAGYAi7CrcCgCL6S6voM4IrDtqQcptlPQwGYAksRrkpVkIZD5JgmeR5IFe4WgK0rAFPkamBRC3BFd2k4AkwSl83RjfVeC74CMCuZSI6NqQ7d8G9KDJOLK3MEvTwY8BdAga0Io3sBa0vEYWEviCOWEDwFYDoZh+HxWDwmb/R18gzSx0Rv4r0FUORa4EfJ5yomj8IEyfNYTNZTbdZbAAU2IJyb6siOB2+4Qlx+3mvisRiInwC2I4yy6Ke1pgw/E5crWwuiPb373QL+BZzcnpBDobpLHGaF6tnLO6kAenmCG4WXFQH8WhwubURGFn/PhgAMD4nLl7KY4EYxZ0MAcBhhqOTZ14iQrP2eFQGU8/ogeb6qC0LVEs+SAMqRL+ctLpdZlRdFeoH32UBTpLc9Br6XbMMuhLUIm+jmzbZSQUdlV9M++rBTpnI4CWxZGwGS4NSWj2eBh4CbxGG3LaM97agA4mLWnt23gZ+yg8VxbHVTAdhLVNyWHqabKbb3NqgA4k6bTfuG+3GYYvNJRgVgM0FJ2DL8QFxutOVKBWCLyaTsGN6gH0NlKq/bcKkCsMFi0jYMs8XlDhtuVQA2WEzahuH34vJlG25VADZYTN7GPnE4yYZbFYANFlth4y362VjSVgG0Ink2fAon2Xi7qQKwkYxW2OglAtiP4QlgN8LLreAxtT4HcL1cwKGo+FsxAnQDv6HEbTKDv0QNQPtHYyBpAZSPm7mSp/ymS682YCA5ARiWMYS5Mon/tUHcCuEoA0kJ4AZx+KGy3n4MJCGA9eJwXqPQzSJyjGAMJU5s1FZ/r8NAH7roYIdM5T9BeIpXAIaXOMKZcgkH/MCYIp8GvgN8A/hQENDaJhADrwG/oy9X1BNDvAIQZkqee+okfwGGa9qq4FQgblPVaC85xsp09nqhjlMAO9nBCK9tTGYjfdhLJ3BRqqhMK1jDdoYw2msCHqcAypsZ53txZoqVo9pz08pnKnEbLhKXe3tij1MAk8VhQ0+HZjWj6GZ7KklMM2jD3eJW5lpVV5wC+IA47K8RQJEVwMVp5jKV2H3OR8YjAMPL4vLRmuSvoYMjvAoMTCWJ6Qa9Vhy+mdQIsEEcJtcIYCWjybE13TymFL2wVPK1dZ/iGgE8S7KYTi7F8KuUUphu2AlPAsu1eose9/9lwPfSzWRq0Q8Xh53J3AI6+IRM4681AiiwBeEzqaUwrcANh8Slvxf8OG4BXezg/T0XgCpr/afxX4S+aeUxtbgNfxCXSUkJYJs4nKXP/20ll5vFYV4yAjCsEJdve9z/y8/+5TUAvZJmwDBDXArJCADmicPNHgLQ5d+kE3/Mn+Hj4vK3ZARg+KK4POIxAdyEMKFVHGTWb/m7Cc9zgl9tgTgmgd5LwAUOIrrZI3EhGraIyzg/v7YFsFcchnhMAE+nm38kHrw6BMMycfl+MgLwObRoikwDVmk+WsCAcJnkWZ6MAOA6cWo/MGUKXI/optAWpB9KnC0zeDoZAQh5ydf+002BhxHOaQkBWXZqKHGQE+odIrU7BxBGSZ7yd/uqLlOsbArVV8DJi9FzUe54GDYF4L0EvIpTKLEr+djVIz67gOIRgOFpcTnb499f3u69VtPREgbmiMPt9TzbHAHuEYeZHgtASxB+3JLws+40x3iZXv/rb/YE4PNhJlNgPWKnnk3W89l0/APo3+gIuT0BwBfEqf3SqCnwCsKHmwavHaIy8Kw4jGxkxKYAapaAzSoGU2JPIxD6ewwMGDrFxWlk2Y4ADHvE5WMe9//zEf2Cd6MkxPJ7wIqidgQAnieATYGfIFwTS4BqtD4DwjmS59FGNNkRgM+WY1Pkt8DXGoHQ32NgoItB9U5lH/NoRwAwXRxWe6wB9N4vj8SQM4smXxCHU4PYsyOADs6Uafz9eIdmDQM54l8XIAg4bROagXXicGGQ3jYE4L0EXOBcpPZwaBBQ2iYiA4YF4la+AN/wsiGAP4vDWI8ngKsQljZEoA3iYOA8cVgfxHB0Afi8cDBF1mgBiCApiKGN8BHJ80oQy9EFAHPF4VaPCeDzwPAgILSNRQYML4nL4KAWowtAmCh5/lg1AXyAE3mDg0FBaDurDASqynbMY3QBQO0S8Eomkqt9L2A1TDXmx8AScVgYlJ6oAnhRHIZ6TADnI9wQFIS2s8rAheKwLqjFqAJ4UBwu8BBAESEfFIS2s8hAjlNlOi8EtRhNAIZrxWWBxwSwvCh0RlAQ2s4SA4YD4jKoGWvRBCB8S/KVx713L6MTwGb4t932UXGa230dTQAlzpAZ1Sd+TIHxCI/ZjkztBWKg6aLcUQTgtwQ8B6ldFwgEXxtFY8DnXEY9o+EFYHhK3Eqh56rLFCu1gWvqA0SLTHsHYkAY2ezHOMILAJaLw2UeAih/BuaTgQBrI3sM1KkDFM8IADV7zs2d9KV/pQ5Qzl5kaikQA4bHxWV8oLbHNYoyAnxeHDZVPQEUGIvwZLMgtL0VBm4XhznNWgovAI8956aTWRh+2SwIbW+BgQbfZvDzEFYAu8XhFI/7/53Ady2EoyaaZ+AscdjWbLdwAjDcL27tZk9T5ClgTLMgtH1EBhrUAYpjEljzxkkLQUZMYrTuW8UJ98cLOwLUfH3CrORT5JofgqLFrb2PMuD5SB6EnXACgNPFYUfVE0Anl5TPowdxqm2sM3C5OPwijNXmBeCz4GCK3AbMDgNC+0RkwDBOXLaEseIngOeAEZ4GDU+Iy2drngAKbEb4XBgQ2icCAwHqADU/CSzwJFK71fuoobvEYVbV8P9OJfA3tRBkhESG7/qMOIwK2917BCiwDuHrPiPAbHG5o0oAqxlJt3ct2rDAtF9ABnyKcwfsjd8tYDH4bCwUJki++n2/KVbOoXtWow4KRNuFZsDzXGZQa34jgP+xLq8l4CI3gnc9+qBAtF0IBgwH6MdgmcrhEL0rXbwFUP68WxevIQyoMmzYJS7DPCaAGxEmhgWh/UIyIMyXPDeF7O0vgPIvpsB1CFf2MH6fOEzxEIBWAo+ShXB915PnfBFMuO7v9PIcASoCWMEH6VNZ7Hlvl6lhsbhc3WMCOJxuysfA9EqKAUO5+P7MeiVgg0LxFUBFBEW+AtwH9DlqsObQgSlWvgBetTM4qHNt1zQD+zEs7PkU1rSV4zrUFcDRW0G50NMtwDBKjJAZ1f92U2ApUlshPAoo7fsuA12YCt+bgXvpxyMylW6b/DQUwDFnZiWn4fLPqPccm+DVVnQGAgsguiu10I4MqADaMSsJYlIBJEh2O7pSAbRjVhLEpAJIkOx2dKUCaMesJIhJBZAg2e3oSgXQjllJEJMKIEGy29GVCqAds5IgJhVAgmS3oysVQDtmJUFM/wdaDlOuM5Eu/AAAAABJRU5ErkJggg==") +} + +.ew-tree-table .ew-tree-icon-file:after { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAJNUlEQVR4Xu2dXYxdVRXHf2tghhYaoba1Qk1owIwmfVBaTKRgQqMPlGjig2nDnDsF0whSnwqJ4SNoU2OLUSNPVDSx2t47hEkxaQMBI1hB/EiE6osYqjGUYPGjCihN6Uy525wzt7UdZu7ZZ87a5949Z52XeVl77bX//9/d52vvM4IdtVZAaj16GzwGQM0hMAAMgJorUPPh2wxgANRcgZoP32YAA6DmCtR8+DYDGADVKuB2s4BB1gMbEYZxLEFYDlxQbSU97+0Ejn8hHMPxR4R9LOZxuZGTVVZW2QzgxlnGBNuBUYSLqhxkNH05jgN7GeIrsoF/VlF3cADcQc7nKHfiuM+M97Q0BUH4GpfxbVnHKc9WcwoLCoBrsRjHYwhr51Rd3Rs5foXwaUl4PZQUwQBwLa4AngZWhiq+JnlfBj4pCX8JMd4gALgxluJ4Hrg8RNE1zHkE4WoZ4Zj22NUBcOMsZILnEFZrF1vrfI5DDHGdbOCEpg76ADTZiXCXZpGWq6OAsFNGuEdTD1UA3B7exwDpdLUgt0jHqwjjwH6EF0NMb7k19DAgO03CKtp8pvNM5AO55TjeZoCVMsLfc2M9A3QBaPEQcGtO328hbOYw+2Qbbc8653WY28YAw3yONrsRLswZ7Pck4TYtQdQAcOMMMckbwMIuxaVPua6VhBe0BjCf8rgWa4Bf5jwVPcEgl8gGJjTGrgfAGDfgeCKnqC2SsEuj8Pmaw7W4HXiw6/iE9TLCkxoa6AHQyopOi5/5cLzCCq4M/WRLQ5Re5ug8Of1z11tox3el0UXrAgPQA6DJQYTru/R9ryTsKFBbbUNdK7vS/3qXH9PPpcE6DYH0AGjxEjA8a1Ft1sgohzSKnu853MNcRburVocl4UMaOugB0MxeYMx+BTt14fKmRtHzPYcb5+LOBfVsp9Pj0mCRhg56ALRw3QqSxPYgFDHMVaSnAVDElQpjDYAKxe7HrgyAfnSlwpoMgArF7seuDIB+dKXCmgyACsXux64MgH50pcKaDIAKxe7HrgyAfnSlwpoMgBnEduO8n0m+j+MahCUV+pHf1dQun18zyBdkA3/Lb9A9wgCYpk9nj8EfEC4tK27Q9o7XGOIjZXf2GADTAWjyQ4Sbg5qnl3yvJGwqk84AePcMkO6VSxdSxnAck4RlZQo1AN4NwF+By8qIWmHbo5Kwokx/BkDcp4A9kpQ7XRkA0wGY2nPw+yguAoVVZTd0GgAz3Qbu5VIGsr0H1wLvLTPFBmj772xJd5vbZJTXyuY3AMoqGHl7AyByA8uWbwCUVTDy9gZA5AaWLd8AKKtg5O0NgMgNLFu+AVBWwcjbGwCRG1i2fAOgrIKRtzcAIjewbPkGQFkFI29vAERuYNnyDYCZXgbZmsAzqmjtto5md7CtCTz3F1E/AGxN4DkE1A+AVvb9fFsT2MGgjgDYmsCz5oD6ARDXKcDWBE6/iC9LbOc7xLYmsK6ngHTcztYE1vc2sOyDldja24Og2BxTrtcAUBY0tnQGQGyOKddrACgLGls6AyA2x5TrNQCUBY0tnQEQm2PK9RoAyoLGls4AiM0x5XoNAGVBY0tnAMTmmHK9BsAMgqp+J1D5u37K/mMATFM02JpApe/6GQCB/8eNC7sgpPR3/QyA0ACEXRNY+rt+BkB4AEKuCSz9XT8DIDQAYU8BpdfwGQChAQj1ncD0IlDhu34GQGAAUoGV1wSqftfPAKgAAG2RQ+Rzu1nAIOuBjQjDOJYgLAcu0Oyv7Crr07VEszdQU7wQudw4y5hgOzCKcFGIPs7OaQCEVtgzvzvI+RzlThz3VWF8p6wJSXRmFJsBPI2eKazzdPIxhLUl0syl6RFJWDmXhtPbGABzVNG1uAJ4GnSMKFSG4zfS4JpCbWYJNgDmoKIbYymO54HL59C8fBPHj6TBLeUTgQFQUEU3zkImeA5hdcGmeuHCRhlhXCOhAVBQRddkJ8JdBZtphr/DIEtkA29qJDUACqjY2aF8BGFBbjPHq0j2K92P8KKMcKxbGzfGKhy/ABbn5N4vCZ/N7d8zwADwFCoNc63sv5XcmtPkLYTNHGafbKPtk76A+dDmwzLKSz55fWIMAB+VUvPHGWKSN4CFXZqcTP+djSS84JmWQuY7xqRB4pvbJ84A8FEpBWCMG3A8kRO+RRJ2eaZMZ5SPAj/zmPbTlEd5h6tkE//wze8TZwD4qDQ1/T8I3D5ruOMVVnClrOOUT8rMfMczCO/JjXdM4vi4jHIoN7ZggAHgKZhrchDh+i7h90rCDp90hcwHB9wiCXt8cheNMQA8FXOt7MJreNbwNmt8fqEFzU/t3ywNfuBZZuEwA8BTMtfkOMKFs4YPcknevblr8jHgKa9pf6qjQtcUnkM5J8wA8FSt7Dr9zHzJLvgWeXYZ3Py0DgPA040yABQ237FVGjzgWVqpME0A/tuVbsfF0uA/partYeO5AtDP5uvOAE3+hPDBWT0aYLXcxO966GGprucCQL+brw3AswifmFVlxz3SYGcpF3rYuCgA7mHW0uYn3ud8x93S4P6qh6h3CmiyC+GLXQAo9KCkaiHy+isCQMf8p3IeG/+/yx6ZrzsDtLgReLyrkI4vSSN7ohbd4QvAHMzfLg2+2itB9GaA9GXJBK93vVeGk7RZ6/PApFeCzNavDwCuxaeAAwV++fdLg7t7OVY1ANJBeL8udXyehEdFssecURx5AAB3AN8EzvMakOMBabDVKzZgkC4AYyynzcveCybgEYQDPgsmAmrgldoDAK88WVCfmK96DXB69K7JNxC+7K9GzSL7yPwwAKSLJid5Fri6Ztb6DHeXJGzxCawqRvUUcGYWmFo2/duerJmvSrni/fSd+UFmgDMQTG2c+Clkf+t+fEeS7CKx744gM8BZEKQrXNPbouv6buTVFHQSx83S4JFquiveS1AAsgvehxhkEXdUvHmyuBL6LZ5hgK39/v4jOABnZoN0+/QkO3DcVOEuWn1bu2V0vA38mPP4Vr8bf3oYlQFwFgjpXcJ6HBshe3u4NMQHFII7ny7UlOy/maYbPtI3oY9yigOyiePB+1bsoHIAFGu3VAoKGAAKIsacwgCI2T2F2g0ABRFjTmEAxOyeQu0GgIKIMacwAGJ2T6F2A0BBxJhTGAAxu6dQuwGgIGLMKf4HAR/hrhUhGSQAAAAASUVORK5CYII=") +} diff --git a/ss-admin/src/main/resources/static/js/lay-module/treetable-lay-3.x/treeTable.js b/ss-admin/src/main/resources/static/js/lay-module/treetable-lay-3.x/treeTable.js new file mode 100644 index 0000000..33be9d6 --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/treetable-lay-3.x/treeTable.js @@ -0,0 +1,2267 @@ +/** 树形表格3.x Created by wangfan on 2020-05-12 https://gitee.com/whvse/treetable-lay */ + +layui.define(['laytpl', 'form', 'util'], function (exports) { + var $ = layui.jquery; + var laytpl = layui.laytpl; + var form = layui.form; + var util = layui.util; + var device = layui.device(); + var MOD_NAME = 'treeTable'; // 模块名 + var _instances = {}; // 记录所有实例 + + /* 表格默认参数 */ + var defaultOption = { + elem: undefined, // 容器 + cols: undefined, // 列参数 + url: undefined, // url模式请求 + method: undefined, // url模式请求方式 + where: undefined, // url模式请求条件 + contentType: undefined, // url模式请求类型 + headers: undefined, // url模式请求headers + parseData: undefined, // url模式处理请求数据 + request: {pidName: 'pid'}, // url模式请求字段自定义 + toolbar: undefined, // 表头工具栏 + defaultToolbar: undefined, // 表头工具栏右侧按钮 + width: undefined, // 容器宽度 + height: undefined, // 容器高度 + cellMinWidth: 90, // 单元格最小宽度 + done: undefined, // 数据处理完回调 + data: undefined, // 直接赋值数据 + title: undefined, // 定义table大标题,文件导出会用到 + skin: undefined, // 表格风格 + even: undefined, // 是否开启隔行变色 + size: undefined, // 表格尺寸 + statusCode: 0, // 数据返回值代码 + text: { + none: '无数据' // 空数据提示 + }, + reqData: undefined, // 自定义加载数据方法 + useAdmin: false, // 是否使用admin.ajax + tree: { + idName: 'id', // id的字段名 + pidName: 'pid', // pid的字段名 + childName: 'children', // children的字段名 + haveChildName: 'haveChild', // 是否有children标识的字段名 + haveChildReverse: false, // 是否将children标识的字段取反 + openName: 'open', // 是否默认展开的字段名 + iconIndex: 0, // 图标列的索引 + arrowType: undefined, // 折叠箭头类型 + onlyIconControl: undefined, // 仅点击图标控制展开折叠 + getIcon: function (d) { // 自定义图标 + var haveChild = d[this.haveChildName]; + if (haveChild !== undefined) { + haveChild = haveChild === true || haveChild === 'true'; + if (this.haveChildReverse) haveChild = !haveChild; + } + else if (d[this.childName]) haveChild = d[this.childName].length > 0; + if (haveChild) return ''; + else return ''; + } + } + }; + /* 列默认参数 */ + var colDefaultOption = { + field: undefined, // 字段名 + title: undefined, // 标题 + width: undefined, // 宽度 + minWidth: undefined, // 最小宽度 + type: 'normal', // 列类型 + fixed: undefined, // 固定列 + hide: undefined, // 是否初始隐藏列 + unresize: undefined, // 禁用拖拽列宽 + style: undefined, // 单元格样式 + align: undefined, // 对齐方式 + colspan: undefined, // 单元格所占的列数 + rowspan: undefined, // 单元格所占的行数 + templet: undefined, // 自定义模板 + toolbar: undefined, // 工具列 + 'class': undefined, // 单元格class + singleLine: undefined // 是否一行显示 + }; + + /** TreeTable类构造方法 */ + var TreeTable = function (options) { + _instances[options.elem.substring(1)] = this; + this.reload(options); + }; + + /** + * 根据ID查找数据 + * @param id 数据条目的ID + */ + TreeTable.prototype.findDataById = function (id) { + var options = this.options; + function each(data) { + for (var i = 0; i < data.length; i++) { + if (data[i][options.tree.idName] === id) return data[i]; + if (data[i][options.tree.childName]) { + var res = each(data[i][options.tree.childName]); + if (res) return res; + } + } + } + return each(options.data); + } + + /** 参数设置 */ + TreeTable.prototype.initOptions = function (opt) { + var that = this; + + // 处理特殊列 + function initCol(item) { + if (!item.INIT_OK) item = $.extend({INIT_OK: true}, colDefaultOption, item); + // 特殊列处理 + if (item.type === 'space') { // 空列 + if (!item.width) item.width = 15; + item.minWidth = item.width; + } else if (item.type === 'numbers') { // 序号列 + if (!item.width) item.width = 40; + item.minWidth = item.width; + if (!item.singleLine) item.singleLine = false; + if (!item.unresize) item.unresize = true; + if (!item.align) item.align = 'center'; + } else if (item.type === 'checkbox' || item.type === 'radio') { // 复/单选框列 + if (!item.width) item.width = 48; + item.minWidth = item.width; + if (!item.singleLine) item.singleLine = false; + if (!item.unresize) item.unresize = true; + if (!item.align) item.align = 'center'; + } + if (item.toolbar) item.type = 'tool'; + return item; + } + + // 初始化列参数 + if ('Array' !== isClass(opt.cols[0])) opt.cols = [opt.cols]; + + // 恢复cols参数初始状态 + for (var m = 0; m < opt.cols.length; m++) { + for (var n = 0; n < opt.cols[m].length; n++) { + opt.cols[m][n].INIT_OK = undefined; + opt.cols[m][n].key = undefined; + opt.cols[m][n].colGroup = undefined; + opt.cols[m][n].HAS_PARENT = undefined; + opt.cols[m][n].parentKey = undefined; + opt.cols[m][n].PARENT_COL_INDEX = undefined; + } + } + + // cols参数处理 + var colArrays = [], colIndex = 0; + for (var i1 = 0; i1 < opt.cols.length; i1++) { + var item1 = opt.cols[i1]; + for (var i2 = 0; i2 < item1.length; i2++) { + var item2 = item1[i2]; + if (!item2) { + item1.splice(i2, 1); + continue; + } + item2 = initCol(item2); + // 合并单元格处理 + item2.key = i1 + '-' + i2; + var CHILD_COLS = undefined; + if (item2.colGroup || item2.colspan > 1) { + item2.colGroup = true; + item2.type = 'group'; + CHILD_COLS = []; + colIndex++; + var childIndex = 0; + for (var i22 = 0; i22 < opt.cols[i1 + 1].length; i22++) { + var item22 = $.extend({INIT_OK: true}, colDefaultOption, opt.cols[i1 + 1][i22]); + if (item22.HAS_PARENT || (childIndex > 1 && childIndex == item2.colspan)) { + opt.cols[i1 + 1][i22] = item22; + continue; + } + item22.HAS_PARENT = true; + item22.parentKey = i1 + '-' + i2; + item22.key = (i1 + 1) + '-' + i22; + item22.PARENT_COL_INDEX = colIndex; + item22 = initCol(item22); + CHILD_COLS.push(item22); + childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1); + opt.cols[i1 + 1][i22] = item22; + } + } + item2.CHILD_COLS = CHILD_COLS; + if (!item2.PARENT_COL_INDEX) colArrays.push(item2); + opt.cols[i1][i2] = item2; + } + } + this.options = $.extend(true, {}, defaultOption, opt); + this.options.colArrays = colArrays; + + // url加载模式转为reqData模式 + if (this.options.url) { + this.options.reqData = function (data, callback) { + if (!that.options.where) that.options.where = {}; + if (data) that.options.where[that.options.request.pidName] = data[that.options.tree.idName]; + (that.options.useAdmin ? layui.admin : $).ajax({ + url: that.options.url, + data: that.options.contentType && that.options.contentType.indexOf('application/json') === 0 ? JSON.stringify(that.options.where) : that.options.where, + headers: that.options.headers, + type: that.options.method, + dataType: 'json', + contentType: that.options.contentType, + success: function (res) { + if (that.options.parseData) res = that.options.parseData(res); + if (res.code == that.options.statusCode) callback(res.data); + else callback(res.msg || '加载失败'); + }, + error: function (xhr) { + callback(xhr.status + ' - ' + xhr.statusText); + } + }); + }; + } else if (this.options.data && this.options.data.length > 0 && this.options.tree.isPidData) { // pid形式数据转children形式 + this.options.data = tt.pidToChildren(this.options.data, this.options.tree.idName, this.options.tree.pidName, this.options.tree.childName); + } + + // toolbar参数处理 + if ('default' === this.options.toolbar) { + this.options.toolbar = [ + '
    ', + '
    ', + ' ', + '
    ', + '
    ', + ' ', + '
    ', + '
    ', + ' ', + '
    ', + '
    ' + ].join(''); + } + if (this.options.defaultToolbar === undefined) this.options.defaultToolbar = ['filter', 'exports', 'print']; + + // 自定义图标参数处理 + if (typeof this.options.tree.getIcon === 'string') { + var icon = this.options.tree.getIcon; + this.options.tree.getIcon = function (d) { + if (icon !== 'ew-tree-icon-style2') return icon; + var haveChild = d[this.haveChildName]; + if (haveChild !== undefined) { + haveChild = haveChild === true || haveChild === 'true'; + if (this.haveChildReverse) haveChild = !haveChild; + } + else if (d[this.childName]) haveChild = d[this.childName].length > 0; + if (haveChild) return ''; + else return ''; + } + } + }; + /** 初始化表格 */ + TreeTable.prototype.init = function () { + var options = this.options; + var $elem = $(options.elem); // 原始表格 + var tbFilter = options.elem.substring(1); // 表格的filter + // 第一次生成树表格dom + $elem.removeAttr('lay-filter'); + if ($elem.next('.ew-tree-table').length === 0) { + $elem.css('display', 'none'); + $elem.after([ + '
    ', + ' ', + '
    ', + '
    ', + '
    ', + '
    ', + '
    ', + '
    ', + ' ', + '
    ', + '
    ', options.text.none || '', '
    ', + '
    ', + '
    ' + ].join('')); + } + // 获取各个组件 + var components = this.getComponents(); + + // 基础参数设置 + if (options.skin) components.$table.attr('lay-skin', options.skin); + if (options.size) components.$table.attr('lay-size', options.size); + if (options.even) components.$table.attr('lay-even', options.even); + + // 头部工具栏 + components.$toolbar.empty(); + if (options.toolbar === false || options.toolbar === undefined) { + components.$toolbar.hide(); + } else { + components.$toolbar.show(); + if (typeof options.toolbar === 'string') { + laytpl($(options.toolbar).html()).render({}, function (html) { + components.$toolbar.html('
    ' + html + '
    '); + }); + } + var tbRights = ['
    ']; + for (var i = 0; i < options.defaultToolbar.length; i++) { + var tbItem; + if ('filter' === options.defaultToolbar[i]) { + tbItem = {title: '筛选', layEvent: 'LAYTABLE_COLS', icon: 'layui-icon-cols'}; + } else if ('exports' === options.defaultToolbar[i]) { + tbItem = {title: '导出', layEvent: 'LAYTABLE_EXPORT', icon: 'layui-icon-export'}; + } else if ('print' === options.defaultToolbar[i]) { + tbItem = {title: '打印', layEvent: 'LAYTABLE_PRINT', icon: 'layui-icon-print'}; + } else { + tbItem = options.defaultToolbar[i]; + } + if (tbItem) { + tbRights.push('
    '); + tbRights.push('
    '); + } + } + components.$toolbar.append(tbRights.join('') + '
    '); + } + + // 固定宽度 + if (options.width) { + components.$view.css('width', options.width); + components.$tHeadGroup.css('width', options.width); + components.$tBodyGroup.css('width', options.width); + } + // 表格尺寸设置 + var colgroupHtml = this.resize(true); + // 生成thead + var headHtml = '' + this.renderBodyTh() + ''; + + // 渲染表头及空的表主体的结构 + components.$tBodyGroup.children('style').remove(); + if (options.height) { // 固定表头 + components.$tHead.html(colgroupHtml + headHtml); + components.$tBody.html(colgroupHtml + ''); + if (options.height.indexOf('full-') === 0) { // 差值高度 + var h = parseFloat(options.height.substring(5)) + components.$toolbar.outerHeight() + + components.$tHeadGroup.outerHeight() + 1; + components.$tBodyGroup.append([ + '' + ].join('')); + components.$tBodyGroup.data('full', h); + components.$tBodyGroup.css('height', ''); + } else { // 固定高度 + components.$tBodyGroup.css('height', options.height); + components.$tBodyGroup.data('full', ''); + } + components.$tHeadGroup.show(); + } else { + components.$tHeadGroup.hide(); + var trH = {lg: 50, sm: 30, md: 38}; + components.$tBodyGroup.append([ + '' + ].join('')); + components.$tBody.html(colgroupHtml + headHtml + ''); + } + form.render('checkbox', tbFilter); // 渲染表头的表单元素 + + // 默认隐藏列修正colspan + function patchHide($tr) { + var parentKey = $tr.data('parent'), pCol; + if (!parentKey) return; + var $parent = components.$table.children('thead').children('tr').children('[data-key="' + parentKey + '"]'); + var colspan = $parent.attr('colspan') - 1; + $parent.attr('colspan', colspan); + if (colspan === 0) $parent.addClass('layui-hide'); + patchHide($parent); + } + + components.$table.children('thead').children('tr').children('th.layui-hide').each(function () { + patchHide($(this)); + }); + + // 渲染数据 + if (options.reqData) { // 异步加载 + this.options.data = undefined; + this.renderBodyAsync(); + } else if (options.data && options.data.length > 0) { + this.renderBodyData(options.data); + } else { + components.$loading.hide(); + components.$empty.show(); + } + }; + + /** 绑定各项事件 */ + TreeTable.prototype.bindEvents = function () { + var that = this; + var options = this.options; + var components = this.getComponents(); + var $allBody = components.$table.children('tbody'); + + /* 行事件公共返回对象 */ + var member = function (ext) { + // 获取行dom + var $tr = $(this); + if (!$tr.is('tr')) { + var $temp = $tr.parent('tr'); + if ($temp.length > 0) $tr = $temp; + else $tr = $tr.parentsUntil('tr').last().parent(); + } + var data = that.getDataByTr($tr); // 行对应数据 + var obj = { + tr: $tr, + data: data, + del: function () { // 删除行 + var index = $tr.data('index'); + var indent = parseInt($tr.data('indent')); + // 删除子级 + $tr.nextAll('tr').each(function () { + if (parseInt($(this).data('indent')) <= indent) return false; + $(this).remove(); + }); + // 更新后面同辈的index + var indexLength = (typeof index === 'number' ? 1 : index.split('-').length); + $tr.nextAll('tr').each(function () { + var $this = $(this); + if (parseInt($this.data('indent')) < indent) return false; + var _index = $this.data('index').toString().split('-'); + _index[indexLength - 1] = parseInt(_index[indexLength - 1]) - 1; + $this.data('index', _index.join('-')); + }); + // 删除当前行 + var $pTr = $tr.prevAll('tr'); + that.del(undefined, index); + $tr.remove(); + that.renderNumberCol(); // 渲染序号列 + // 联动父级多选框 + $pTr.each(function () { + var tInd = parseInt($(this).data('indent')); + if (tInd >= indent) return true; + that.checkParentCB($(this)); + indent = tInd; + }); + that.checkChooseAllCB(); // 联动全选框 + if (options.data.length === 0) components.$empty.show(); + updateFixedTbHead(components.$view); // 更新滚动条补丁 + }, + update: function (fields) { // 修改行 + data = $.extend(true, data, fields); + var indent = parseInt($tr.data('indent')); + that.renderBodyTr(data, indent, undefined, $tr); // 更新界面 + form.render(null, components.filter); // 渲染表单元素 + that.renderNumberCol(); // 渲染序号列 + // 联动父级多选框 + $tr.prevAll('tr').each(function () { + var tInd = parseInt($(this).data('indent')); + if (tInd >= indent) return true; + that.checkParentCB($(this)); + indent = tInd; + }); + that.checkChooseAllCB(); // 联动全选框 + } + }; + return $.extend(obj, ext); + }; + + // 绑定折叠展开事件 + $allBody.off('click.fold').on('click.fold', '.ew-tree-pack', function (e) { + layui.stope(e); + var $tr = $(this).parentsUntil('tr').last().parent(); + if ($tr.hasClass('ew-tree-table-loading')) return; // 已是加载中 + var haveChild = $tr.data('have-child'); + if (haveChild !== true && haveChild !== 'true') return; // 子节点 + var open = $tr.hasClass('ew-tree-table-open'); + var data = that.getDataByTr($tr); + if (!open && !data[options.tree.childName]) { + that.renderBodyAsync(data, $tr); + } else { + data[options.tree.openName] = toggleRow($tr); + } + }); + + // 绑定lay-event事件 + $allBody.off('click.tool').on('click.tool', '*[lay-event]', function (e) { + layui.stope(e); + var $this = $(this); + layui.event.call(this, MOD_NAME, 'tool(' + components.filter + ')', member.call(this, { + event: $this.attr('lay-event') + })); + }); + + // 绑定单选框事件 + form.on('radio(' + components.radioFilter + ')', function (data) { + var d = that.getDataByTr($(data.elem).parentsUntil('tr').last().parent()); + that.removeAllChecked(); + d.LAY_CHECKED = true; // 同时更新数据 + d.LAY_INDETERMINATE = false; + layui.event.call(this, MOD_NAME, 'checkbox(' + components.filter + ')', + {checked: true, data: d, type: 'one'}); + }); + + // 绑定复选框事件 + form.on('checkbox(' + components.checkboxFilter + ')', function (data) { + var checked = data.elem.checked; + var $cb = $(data.elem); + var $layCb = $cb.next('.layui-form-checkbox'); + // 如果是半选状态,点击全选 + if (!checked && $cb.hasClass('ew-form-indeterminate')) { + checked = true; + $cb.prop('checked', checked); + $layCb.addClass('layui-form-checked'); + $cb.removeClass('ew-form-indeterminate'); + } + var $tr = $cb.parentsUntil('tr').last().parent(); + var d = that.getDataByTr($tr); + d.LAY_CHECKED = checked; // 同时更新数据 + d.LAY_INDETERMINATE = false; + // 联动操作 + if (d[options.tree.childName] && d[options.tree.childName].length > 0) { + that.checkSubCB($tr, checked); // 联动子级 + } + var indent = parseInt($tr.data('indent')); + $tr.prevAll('tr').each(function () { + var tInd = parseInt($(this).data('indent')); + if (tInd < indent) { + that.checkParentCB($(this)); // 联动父级 + indent = tInd; + } + }); + that.checkChooseAllCB(); // 联动全选框 + // 回调事件 + layui.event.call(this, MOD_NAME, 'checkbox(' + components.filter + ')', + {checked: checked, data: d, type: 'more'}); + }); + + // 绑定全选复选框事件 + form.on('checkbox(' + components.chooseAllFilter + ')', function (data) { + var checked = data.elem.checked; + var $cb = $(data.elem); + var $layCb = $cb.next('.layui-form-checkbox'); + if (!options.data || options.data.length === 0) { // 如果数据为空 + $cb.prop('checked', false); + $layCb.removeClass('layui-form-checked'); + $cb.removeClass('ew-form-indeterminate'); + return; + } + // 如果是半选状态,点击全选 + if (!checked && $cb.hasClass('ew-form-indeterminate')) { + checked = true; + $cb.prop('checked', checked); + $layCb.addClass('layui-form-checked'); + $cb.removeClass('ew-form-indeterminate'); + } + layui.event.call(this, MOD_NAME, 'checkbox(' + components.filter + ')', {checked: checked, type: 'all'}); + that.checkSubCB(components.$tBody.children('tbody'), checked); // 联动操作 + }); + + // 绑定行单击事件 + $allBody.off('click.row').on('click.row', 'tr', function () { + layui.event.call(this, MOD_NAME, 'row(' + components.filter + ')', member.call(this, {})); + }); + + // 绑定行双击事件 + $allBody.off('dblclick.rowDouble').on('dblclick.rowDouble', 'tr', function () { + layui.event.call(this, MOD_NAME, 'rowDouble(' + components.filter + ')', member.call(this, {})); + }); + + // 绑定单元格点击事件 + $allBody.off('click.cell').on('click.cell', 'td', function (e) { + var $td = $(this); + var type = $td.data('type'); + // 判断是否是复选框、单选框列 + if (type === 'checkbox' || type === 'radio') return layui.stope(e); + var edit = $td.data('edit'); + var field = $td.data('field'); + if (edit) { // 开启了单元格编辑 + layui.stope(e); + if ($allBody.find('.ew-tree-table-edit').length > 0) return; + var index = $td.data('index'); + var indent = $td.find('.ew-tree-table-indent').length; + var d = that.getDataByTr($td.parent()); + if ('text' === edit || 'number' === edit) { // 文本框 + var $input = $(''); + $input[0].value = d[field]; + $td.append($input); + $input.focus(); + $input.blur(function () { + var value = $(this).val(); + if (value == d[field]) return $(this).remove(); + var rs = layui.event.call(this, MOD_NAME, 'edit(' + components.filter + ')', member.call(this, + {value: value, field: field})); + if (rs === false) { + $(this).addClass('layui-form-danger'); + $(this).focus(); + } else { + d[field] = value; // 同步更新数据 + var keys = $td.data('key').split('-'); + that.renderBodyTd(d, indent, index, $td, options.cols[keys[0]][keys[1]]); // 更新单元格 + } + }); + } else { + console.error('不支持的单元格编辑类型:' + edit); + } + } else { // 回调单元格点击事件 + var rs = layui.event.call(this, MOD_NAME, 'cell(' + components.filter + ')', member.call(this, + {td: $td, field: field})); + if (rs === false) layui.stope(e); + } + }); + + // 绑定单元格双击事件 + $allBody.off('dblclick.cellDouble').on('dblclick.cellDouble', 'td', function (e) { + var $td = $(this); + var type = $td.data('type'); + // 判断是否是复选框、单选框列 + if (type === 'checkbox' || type === 'radio') return layui.stope(e); + var edit = $td.data('edit'); + var field = $td.data('field'); + if (edit) return layui.stope(e); // 开启了单元格编辑 + // 回调单元格双击事件 + var rs = layui.event.call(this, MOD_NAME, 'cellDouble(' + components.filter + ')', member.call(this, + {td: $td, field: field})); + if (rs === false) layui.stope(e); + }); + + // 绑定头部工具栏事件 + components.$toolbar.off('click.toolbar').on('click.toolbar', '*[lay-event]', function (e) { + layui.stope(e); + var $this = $(this); + var event = $this.attr('lay-event'); + if ('LAYTABLE_COLS' === event) that.toggleCol(); + else if ('LAYTABLE_EXPORT' === event) that.exportData('show'); + else if ('LAYTABLE_PRINT' === event) that.printTable(); + else layui.event.call(this, MOD_NAME, 'toolbar(' + components.filter + ')', {event: event, elem: $this}); + }); + + // 同步滚动条 + components.$tBodyGroup.on('scroll', function () { + var $this = $(this); + components.$tHeadGroup.scrollLeft($this.scrollLeft()); + }); + + // 导出数据 + components.$toolbar.off('click.export').on('click.export', '.layui-table-tool-panel>[data-type]', function () { + var type = $(this).data('type'); + if ('csv' === type || 'xls' === type) that.exportData(type); + }); + components.$toolbar.off('click.panel').on('click.panel', '.layui-table-tool-panel', function (e) { + layui.stope(e); + }); + + // 筛选列 + form.on('checkbox(' + components.colsToggleFilter + ')', function (data) { + that.toggleCol(data.elem.checked, undefined, data.value); + }); + + }; + + /** 获取各个组件 */ + TreeTable.prototype.getComponents = function () { + var $view = $(this.options.elem).next('.ew-tree-table'); // 容器 + var filter = $view.attr('lay-filter'); // 容器filter + var $tHeadGroup = $view.children('.ew-tree-table-head'); // 表头部分容器 + var $tBodyGroup = $view.children('.ew-tree-table-box'); // 主体部分容器 + return { + $view: $view, + filter: filter, + $tHeadGroup: $tHeadGroup, + $tBodyGroup: $tBodyGroup, + $tHead: $tHeadGroup.children('.layui-table'), // 表头表格 + $tBody: $tBodyGroup.children('.layui-table'), // 主体表格 + $table: $view.find('.layui-table'), // 所有表格 + $toolbar: $view.children('.ew-tree-table-tool'), // 头部工具栏 + $empty: $tBodyGroup.children('.ew-tree-table-empty'), // 空视图 + $loading: $tBodyGroup.children('.ew-tree-table-loading'), // 加载视图 + checkboxFilter: 'ew_tb_checkbox_' + filter, // 复选框filter + radioFilter: 'ew_tb_radio_' + filter, // 单选框filter + chooseAllFilter: 'ew_tb_choose_all_' + filter, // 全选按钮filter + colsToggleFilter: 'ew_tb_toggle_cols' + filter // 筛选列的filter + }; + }; + + /** + * 遍历表头 + * @param callback + * @param obj + */ + TreeTable.prototype.eachCols = function (callback, obj) { + if (!obj) obj = this.options.colArrays; + for (var i = 0; i < obj.length; i++) { + var item = obj[i]; + callback && callback(i, item); + if (item.CHILD_COLS) this.eachCols(callback, item.CHILD_COLS); + } + }; + + /** + * 遍历数据 + * @param callback + * @param data + */ + TreeTable.prototype.eachData = function (callback, data) { + if (!data) data = this.options.data; + for (var i = 0; i < data.length; i++) { + var item = data[i]; + callback && callback(i, item); + if (item[this.options.tree.childName]) this.eachData(callback, item[this.options.tree.childName]); + } + }; + + /** + * 异步加载渲染 + * @param d 父级数据 + * @param $tr 父级dom + */ + TreeTable.prototype.renderBodyAsync = function (d, $tr) { + var that = this; + var options = this.options; + var components = this.getComponents(); + // 显示loading + if ($tr) { + $tr.addClass('ew-tree-table-loading'); + $tr.find('.ew-tree-pack').children('.ew-tree-table-arrow').addClass('layui-anim layui-anim-rotate layui-anim-loop'); + } else { + components.$empty.hide(); + if (options.data && options.data.length > 0) components.$loading.addClass('ew-loading-float'); + components.$loading.show(); + } + // 请求数据 + options.reqData(d, function (data) { + if (typeof data !== 'string' && data && data.length > 0 && options.tree.isPidData) { + data = tt.pidToChildren(data, options.tree.idName, options.tree.pidName, options.tree.childName); + } + that.renderBodyData(data, d, $tr); // 渲染内容 + }); + }; + + /** + * 根据数据渲染body + * @param data 数据集合 + * @param d 父级数据 + * @param $tr 父级dom + */ + TreeTable.prototype.renderBodyData = function (data, d, $tr) { + var msg; + if (typeof data === 'string') { + msg = data; + data = []; + } + var that = this; + var options = this.options; + var components = this.getComponents(); + // 更新到数据 + if (d === undefined) options.data = data; + else d[options.tree.childName] = data; + var indent; + if (d && $tr) { + indent = parseInt($tr.data('indent')) + 1; + d[options.tree.openName] = true; + } + var htmlStr = this.renderBody(data, indent, d); + if (d && $tr) { + // 移除旧dom + $tr.nextAll('tr').each(function () { + if (parseInt($(this).data('indent')) <= (indent - 1)) return false; + $(this).remove(); + }); + // 渲染新dom + $tr.after(htmlStr).addClass('ew-tree-table-open'); + } else { + components.$tBody.children('tbody').html(htmlStr); + } + form.render(null, components.filter); // 渲染表单元素 + this.renderNumberCol(); // 渲染序号列 + if (d && $tr) { + // 更新父级复选框状态 + this.checkParentCB($tr); + $tr.prevAll('tr').each(function () { + var tInd = parseInt($(this).data('indent')); + if (tInd < (indent - 1)) { + that.checkParentCB($(this)); + indent = tInd + 1; + } + }); + // 移除loading + $tr.removeClass('ew-tree-table-loading'); + var $arrow = $tr.find('.ew-tree-pack').children('.ew-tree-table-arrow'); + $arrow.removeClass('layui-anim layui-anim-rotate layui-anim-loop'); + if (msg) { // 加载失败 + $tr.removeClass('ew-tree-table-open'); + } else if (data && data.length === 0) { // 无子集 + d[options.tree.haveChildName] = !!options.tree.haveChildReverse; + $tr.data('have-child', false); + $arrow.addClass('ew-tree-table-arrow-hide'); + $arrow.next('.ew-tree-icon').after(options.tree.getIcon(d)).remove(); + } + } else { + // 移除loading + components.$loading.hide(); + components.$loading.removeClass('ew-loading-float'); + // 显示空视图 + if (data && data.length > 0) { + components.$empty.hide(); + } else { + components.$empty.show(); + if (msg) components.$empty.text(msg); + else components.$empty.html(options.text.none); + } + } + this.checkChooseAllCB(); // 联动全选框 + updateFixedTbHead(components.$view); // 滚动条补丁 + options.done && options.done(data); + }; + + /** + * 递归渲染表格主体部分 + * @param data 数据列表 + * @param indent 缩进大小 + * @param parent 父级 + * @param h 父级是否隐藏 + * @returns {string} + */ + TreeTable.prototype.renderBody = function (data, indent, parent, h) { + var options = this.options; + if (!indent) indent = 0; + var html = ''; + if (!data || data.length === 0) return html; + var hide = parent ? !parent[options.tree.openName] : undefined; + if (h) hide = h;//当所有父级存在隐藏时,隐藏所有子集 + for (var i = 0; i < data.length; i++) { + var d = data[i]; + d.LAY_INDEX = (parent ? parent.LAY_INDEX + '-' : '') + i; + html += this.renderBodyTr(d, indent, hide); + // 递归渲染子集 + html += this.renderBody(d[options.tree.childName], indent + 1, d, h); + } + return html; + }; + + /** + * 渲染每一行数据 + * @param d 行数据 + * @param indent 缩进大小 + * @param hide 是否隐藏 + * @param $tr + * @returns {string} + */ + TreeTable.prototype.renderBodyTr = function (d, indent, hide, $tr) { + var that = this; + var options = this.options; + if (!indent) indent = 0; + var haveChild = d[options.tree.haveChildName]; + if (options.tree.haveChildReverse) haveChild = !haveChild; + if (haveChild === undefined) haveChild = d[options.tree.childName] && d[options.tree.childName].length > 0; + if ($tr) { + $tr.data('have-child', haveChild ? 'true' : 'false'); + $tr.data('indent', indent); + $tr.removeClass('ew-tree-table-loading'); + } + var html = ''); + var index = 0; + this.eachCols(function (i, col) { + if (col.colGroup) return; + html += that.renderBodyTd(d, indent, index, $tr ? $tr.children('td').eq(index) : undefined, col); + index++; + }); + html += ''; + return html; + }; + + /** + * 渲染每一个单元格数据 + * @param d 行数据 + * @param indent 缩进大小 + * @param index 第几列 + * @param $td + * @param col + * @returns {string} + */ + TreeTable.prototype.renderBodyTd = function (d, indent, index, $td, col) { + if (!col||col.colGroup) return ''; + var options = this.options; + var components = this.getComponents(); + if (!indent) indent = 0; + // 内容填充 + var content = '', cell = '', icon = ''; + if (col.type === 'numbers') { // 序号列 + content = ''; + } else if (col.type === 'checkbox') { // 复选框列 + content = [ + '' + ].join(''); + } else if (col.type === 'radio') { // 单选框列 + content = [ + '' + ].join(''); + } else if (col.templet) { // 自定义模板 + if (typeof col.templet === 'function') { + content = col.templet(d); + } else if (typeof col.templet === 'string') { + laytpl($(col.templet).html()).render(d, function (html) { + content = html; + }); + } + } else if (col.toolbar) { // 操作列 + if (typeof col.toolbar === 'function') { + content = col.toolbar(d); + } else if (typeof col.toolbar === 'string') { + laytpl($(col.toolbar).html()).render(d, function (html) { + content = html; + }); + } + } else if (col.field && d[col.field] !== undefined && d[col.field] !== null) { // 普通字段 + content = util.escape(d[col.field] === 0 ? '0' : d[col.field]); + } + // 图标列处理 + if (index === options.tree.iconIndex) { + // 缩进 + for (var i = 0; i < indent; i++) icon += ''; + icon += ''; + // 加箭头 + var haveChild = d[options.tree.haveChildName]; + if (options.tree.haveChildReverse) haveChild = !haveChild; + if (haveChild === undefined) haveChild = d[options.tree.childName] && d[options.tree.childName].length > 0; + icon += (''); + // 加图标 + icon += options.tree.getIcon(d); + content = '' + content + ''; + if (options.tree.onlyIconControl) content = icon + '' + content; + else content = icon + content + ''; + } + cell = [ + '
    ', + '
    ', content, '
    ', + ' ', + ' ', + '
    ' + ].join(''); + + if ($td) $td.html(cell); + + var html = '' + cell + ''); + return html; + }; + + /** + * 渲染表头 + * @returns {string} + */ + TreeTable.prototype.renderBodyTh = function () { + var options = this.options; + var components = this.getComponents(); + var html = []; + $.each(options.cols, function (i1, item1) { + html.push(''); + $.each(item1, function (i2, item2) { + html.push(''); + html.push('
    '); + html.push('
    '); + // 标题 + var ca = ''; + if (item2.type === 'checkbox') html.push(ca); + else html.push(item2.title || ''); + html.push('
    '); + html.push('
    '); + // 列宽拖拽 + if (!item2.colGroup && !item2.unresize) html.push(''); + html.push(''); + }); + html.push(''); + }); + return html.join(''); + }; + + /** 重置表格尺寸 */ + TreeTable.prototype.resize = function (returnColgroup) { + // 计算表格宽度、最小宽度、百分比宽度 + var options = this.options; + var components = this.getComponents(); + var minWidth = 1, width = 1, needSetWidth = true, mwPercent = 0; + this.eachCols(function (i, item) { + if (item.colGroup || item.hide) return; + if (item.width) { + width += (item.width + 1); + if (item.minWidth) { + if (item.width < item.minWidth) item.width = item.minWidth; + } else if (item.width < options.cellMinWidth) item.width = options.cellMinWidth; + } else needSetWidth = false; + if (item.width) minWidth += (item.width + 1); + else if (item.minWidth) { + minWidth += (item.minWidth + 1); + mwPercent += item.minWidth; + } else { + minWidth += (options.cellMinWidth + 1); + mwPercent += options.cellMinWidth; + } + }); + if (minWidth) { + components.$tHead.css('min-width', minWidth); + components.$tBody.css('min-width', minWidth); + } else { + components.$tHead.css('min-width', 'auto'); + components.$tBody.css('min-width', 'auto'); + } + if (needSetWidth) { + components.$tHead.css('width', width); + components.$tBody.css('width', width); + } else { + components.$tHead.css('width', '100%'); + components.$tBody.css('width', '100%'); + } + + // 生成colgroup + var colgroupHtml = []; + this.eachCols(function (i, item) { + if (item.colGroup || item.hide) return; + colgroupHtml.push(''); + }); + colgroupHtml = colgroupHtml.join(''); + if (returnColgroup) return '' + colgroupHtml + ''; + components.$table.children('colgroup').html(colgroupHtml); + }; + + /** 获取行对应数据 */ + TreeTable.prototype.getDataByTr = function ($tr) { + var data, index; + if (typeof $tr !== 'string' && typeof $tr !== 'number') { + if ($tr) index = $tr.data('index'); + } else index = $tr; + if (index === undefined) return; + if (typeof index === 'number') index = [index]; + else index = index.split('-'); + for (var i = 0; i < index.length; i++) { + if (data) data = data[this.options.tree.childName][index[i]]; + else data = this.options.data[index[i]]; + } + return data; + }; + + /** + * 联动子级复选框状态 + * @param $tr 当前tr的dom + * @param checked + */ + TreeTable.prototype.checkSubCB = function ($tr, checked) { + var that = this; + var components = this.getComponents(); + var indent = -1, $trList; + if ($tr.is('tbody')) { + $trList = $tr.children('tr'); + } else { + indent = parseInt($tr.data('indent')); + $trList = $tr.nextAll('tr'); + } + $trList.each(function () { + if (parseInt($(this).data('indent')) <= indent) return false; + var $cb = $(this).children('td').find('input[lay-filter="' + components.checkboxFilter + '"]'); + $cb.prop('checked', checked); + $cb.removeClass('ew-form-indeterminate'); + if (checked) $cb.next('.layui-form-checkbox').addClass('layui-form-checked'); + else $cb.next('.layui-form-checkbox').removeClass('layui-form-checked'); + var d = that.getDataByTr($(this)); + d.LAY_CHECKED = checked; // 同步更新数据 + d.LAY_INDETERMINATE = false; + }); + }; + + /** + * 联动父级复选框状态 + * @param $tr 父级的dom + */ + TreeTable.prototype.checkParentCB = function ($tr) { + var options = this.options; + var components = this.getComponents(); + var d = this.getDataByTr($tr); + var ckNum = 0, unCkNum = 0; + if (d[options.tree.childName]) { + function checkNum(data) { + for (var i = 0; i < data.length; i++) { + if (data[i].LAY_CHECKED) ckNum++; + else unCkNum++; + if (data[i][options.tree.childName]) checkNum(data[i][options.tree.childName]); + } + } + + checkNum(d[options.tree.childName]); + } + var $cb = $tr.children('td').find('input[lay-filter="' + components.checkboxFilter + '"]'); + if (ckNum > 0 && unCkNum === 0) { // 全选 + $cb.prop('checked', true); + $cb.removeClass('ew-form-indeterminate'); + $cb.next('.layui-form-checkbox').addClass('layui-form-checked'); + d.LAY_CHECKED = true; // 同步更新数据 + d.LAY_INDETERMINATE = false; + } else if (ckNum === 0 && unCkNum > 0) { // 全不选 + $cb.prop('checked', false); + $cb.removeClass('ew-form-indeterminate'); + $cb.next('.layui-form-checkbox').removeClass('layui-form-checked'); + d.LAY_CHECKED = false; // 同步更新数据 + d.LAY_INDETERMINATE = false; + } else if (ckNum > 0 && unCkNum > 0) { // 半选 + $cb.prop('checked', true); + $cb.data('indeterminate', 'true'); + $cb.addClass('ew-form-indeterminate'); + $cb.next('.layui-form-checkbox').addClass('layui-form-checked'); + d.LAY_CHECKED = true; // 同步更新数据 + d.LAY_INDETERMINATE = true; + } + }; + + /** 联动全选复选框 */ + TreeTable.prototype.checkChooseAllCB = function () { + var options = this.options; + var components = this.getComponents(); + var ckNum = 0, unCkNum = 0; + + function checkNum(data) { + for (var i = 0; i < data.length; i++) { + if (data[i].LAY_CHECKED) ckNum++; + else unCkNum++; + if (data[i][options.tree.childName]) checkNum(data[i][options.tree.childName]); + } + } + + checkNum(options.data); + + var $cb = components.$view.find('input[lay-filter="' + components.chooseAllFilter + '"]'); + if (ckNum > 0 && unCkNum === 0) { // 全选 + $cb.prop('checked', true); + $cb.removeClass('ew-form-indeterminate'); + $cb.next('.layui-form-checkbox').addClass('layui-form-checked'); + } else if ((ckNum === 0 && unCkNum > 0) || (ckNum === 0 && unCkNum === 0)) { // 全不选 + $cb.prop('checked', false); + $cb.removeClass('ew-form-indeterminate'); + $cb.next('.layui-form-checkbox').removeClass('layui-form-checked'); + } else if (ckNum > 0 && unCkNum > 0) { // 半选 + $cb.prop('checked', true); + $cb.addClass('ew-form-indeterminate'); + $cb.next('.layui-form-checkbox').addClass('layui-form-checked'); + } + }; + + /** 填充序号列 */ + TreeTable.prototype.renderNumberCol = function () { + this.getComponents().$tBody.children('tbody').children('tr').each(function (i) { + $(this).children('td').find('.ew-tree-table-numbers').text(i + 1); + }); + }; + + /** 根据id获取tr的index */ + TreeTable.prototype.getIndexById = function (id) { + var options = this.options; + + function each(data, pi) { + for (var i = 0; i < data.length; i++) { + if (data[i][options.tree.idName] === id) return pi !== undefined ? pi + '-' + i : i; + if (data[i][options.tree.childName]) { + var res = each(data[i][options.tree.childName], pi !== undefined ? pi + '-' + i : i); + //值不为undefined才return + if (res) return res; + } + } + } + + return each(options.data); + }; + + /** 展开指定行 */ + TreeTable.prototype.expand = function (id, cascade) { + var components = this.getComponents(); + var $tr = components.$table.children('tbody').children('tr[data-index="' + this.getIndexById(id) + '"]'); + if (!$tr.hasClass('ew-tree-table-open')) $tr.children('td').find('.ew-tree-pack').trigger('click'); + if (cascade === false) return; + // 联动父级 + var indent = parseInt($tr.data('indent')); + $tr.prevAll('tr').each(function () { + var tInd = parseInt($(this).data('indent')); + if (tInd < indent) { + if (!$(this).hasClass('ew-tree-table-open')) { + $(this).children('td').find('.ew-tree-pack').trigger('click'); + } + indent = tInd; + } + }); + }; + + /** 折叠指定行 */ + TreeTable.prototype.fold = function (id) { + var components = this.getComponents(); + var $tr = components.$table.children('tbody').children('tr[data-index="' + this.getIndexById(id) + '"]'); + if ($tr.hasClass('ew-tree-table-open')) $tr.children('td').find('.ew-tree-pack').trigger('click'); + }; + + /** 全部展开 */ + TreeTable.prototype.expandAll = function () { + this.getComponents().$table.children('tbody').children('tr').each(function () { + if (!$(this).hasClass('ew-tree-table-open')) $(this).children('td').find('.ew-tree-pack').trigger('click'); + }); + }; + + /** 全部折叠 */ + TreeTable.prototype.foldAll = function () { + this.getComponents().$table.children('tbody').children('tr').each(function () { + if ($(this).hasClass('ew-tree-table-open')) $(this).children('td').find('.ew-tree-pack').trigger('click'); + }); + }; + + /** 获取当前数据 */ + TreeTable.prototype.getData = function () { + return this.options.data; + }; + + /** 重载表格 */ + TreeTable.prototype.reload = function (opt) { + this.initOptions(this.options ? $.extend(true, this.options, opt) : opt); + this.init(); // 初始化表格 + this.bindEvents(); // 绑定事件 + }; + + /** 获取当前选中行 */ + TreeTable.prototype.checkStatus = function (needIndeterminate) { + if (needIndeterminate === undefined) needIndeterminate = true; + var list = []; + this.eachData(function (i, item) { + if ((needIndeterminate || !item.LAY_INDETERMINATE) && item.LAY_CHECKED) + list.push($.extend({isIndeterminate: item.LAY_INDETERMINATE}, item)); + }); + return list; + }; + + /** 设置复/单选框选中 */ + TreeTable.prototype.setChecked = function (ids) { + var that = this; + var components = this.getComponents(); + var $radio = components.$table.find('input[lay-filter="' + components.radioFilter + '"]'); + if ($radio.length > 0) { // 开启了单选框 + $radio.each(function () { + var d = that.getDataByTr($(this).parentsUntil('tr').parent()); + if (d && ids[ids.length - 1] == d[that.options.tree.idName]) { + $(this).next('.layui-form-radio').trigger('click'); + return false; + } + }); + } else { // 开启了复选框 + components.$table.find('input[lay-filter="' + components.checkboxFilter + '"]').each(function () { + var $cb = $(this); + var $layCb = $cb.next('.layui-form-checkbox'); + var checked = $cb.prop('checked'); + var indeterminate = $cb.hasClass('ew-form-indeterminate'); + var d = that.getDataByTr($cb.parentsUntil('tr').parent()); + for (var i = 0; i < ids.length; i++) { + if (d && ids[i] == d[that.options.tree.idName]) { + if (d[that.options.tree.childName] && d[that.options.tree.childName].length > 0) continue; + if (!checked || indeterminate) $layCb.trigger('click'); + } + } + }); + } + }; + + /** 移除全部选中 */ + TreeTable.prototype.removeAllChecked = function () { + this.checkSubCB(this.getComponents().$table.children('tbody'), false); + }; + + /** 导出 */ + TreeTable.prototype.exportData = function (type) { + var components = this.getComponents(); + if ('show' === type) { + components.$toolbar.find('.layui-table-tool-panel').remove(); + components.$toolbar.find('[lay-event="LAYTABLE_EXPORT"]').append([ + '
      ', + '
    • 导出到 Csv 文件
    • ', + '
    • 导出到 Excel 文件
    • ', + '
    ' + ].join('')); + } else { + if (device.ie) return layer.msg('不支持ie导出'); + if (!type) type = 'xls'; + var head = [], body = []; + this.eachCols(function (i, item) { + if (item.type !== 'normal' || item.hide) return; + head.push(item.title || ''); + }); + components.$tBody.children('tbody').children('tr').each(function () { + var items = []; + $(this).children('td').each(function () { + var $this = $(this); + if ($this.data('type') !== 'normal' || $this.hasClass('layui-hide')) return true; + items.push($this.text().trim().replace(/,/g, ',')); + }); + body.push(items.join(',')); + }); + // 创建下载文件的a标签 + var alink = document.createElement('a'); + var content = encodeURIComponent(head.join(',') + '\r\n' + body.join('\r\n')); + var contentType = ({csv: 'text/csv', xls: 'application/vnd.ms-excel'})[type]; + alink.href = 'data:' + contentType + ';charset=utf-8,\ufeff' + content; + alink.download = (this.options.title || 'table') + '.' + type; + document.body.appendChild(alink); + alink.click(); + document.body.removeChild(alink); + } + }; + + /** 打印 */ + TreeTable.prototype.printTable = function () { + var components = this.getComponents(); + var head = components.$tHead.children('thead').html(); + if (!head) head = components.$tBody.children('thead').html(); + var body = components.$tBody.children('tbody').html(); + var colgroup = components.$tBody.children('colgroup').html(); + var $html = $([ + '', + ' ', colgroup, '', + ' ', head, '', + ' ', body, '', + '
    ' + ].join('')); + + // 隐藏特殊列 + $html.find('col[data-type="checkbox"],col[data-type="radio"],col[data-type="tool"]').remove(); + $html.find('td[data-type="checkbox"],td[data-type="radio"],td[data-type="tool"],.layui-hide').remove(); + + function hideCol($temp) { + var parentKey = $temp.data('parent'), pCol; + if (!parentKey) return; + var $parent = $html.children('thead').children('tr').children('[data-key="' + parentKey + '"]'); + var colspan = parseInt($parent.attr('colspan')) - 1; + $parent.attr('colspan', colspan); + if (colspan === 0) $parent.remove(); + hideCol($parent); + } + + $html.find('th[data-type="checkbox"],th[data-type="radio"],th[data-type="tool"]').each(function () { + hideCol($(this)); + }).remove(); + + // 打印内容样式 + var style = [ + '' + ].join(''); + var pWindow = window.open('', '_blank'); + pWindow.focus(); + var pDocument = pWindow.document; + pDocument.open(); + pDocument.write($html[0].outerHTML + style); + pDocument.close(); + pWindow.print(); + pWindow.close(); + }; + + /** 筛选列 */ + TreeTable.prototype.toggleCol = function (show, field, key) { + var components = this.getComponents(); + if (show === undefined) { + components.$toolbar.find('.layui-table-tool-panel').remove(); + var cols = ['
      ']; + this.eachCols(function (i, item) { + if (item.type !== 'normal') return; + cols.push('
    • '); + }); + components.$toolbar.find('[lay-event="LAYTABLE_COLS"]').append(cols.join('') + '
    '); + form.render('checkbox', components.filter); + } else { + if (key) { + var $td = components.$table.children('tbody').children('tr').children('[data-key="' + key + '"]'); + var $th = components.$table.children('thead').children('tr').children('[data-key="' + key + '"]'); + if (show) { + $td.removeClass('layui-hide'); + $th.removeClass('layui-hide'); + } else { + $td.addClass('layui-hide'); + $th.addClass('layui-hide'); + } + // 同步更新数据 + var ks = key.split('-'); + var col = this.options.cols[ks[0]][ks[1]]; + col.hide = !show; + + // 更新colspan数据 + function changeParent($temp) { + var parentKey = $temp.data('parent'), pCol; + if (!parentKey) return; + var $parent = components.$table.children('thead').children('tr').children('[data-key="' + parentKey + '"]'); + var colspan = $parent.attr('colspan'); + show ? colspan++ : colspan--; + $parent.attr('colspan', colspan); + if (colspan === 0) $parent.addClass('layui-hide'); + else $parent.removeClass('layui-hide'); + changeParent($parent); + } + + changeParent($th); + + // 同步eachCols数据 + this.eachCols(function (i, item) { + if (item.key === key) item.hide = col.hide; + }); + this.resize(); // 更新表格尺寸 + } + } + }; + + /** + * 搜索数据 + * @param ids 关键字或数据id集合 + */ + TreeTable.prototype.filterData = function (ids) { + var components = this.getComponents(); + components.$loading.show(); + if (this.options.data.length > 0) components.$loading.addClass('ew-loading-float'); + var $trList = components.$table.children('tbody').children('tr'); + var indexList = []; + if (typeof ids === 'string') { // 关键字 + $trList.each(function () { + var index = $(this).data('index'); + $(this).children('td').each(function () { + if ($(this).text().indexOf(ids) !== -1) { + indexList.push(index); + return false; + } + }); + }); + } else { + for (var i = 0; i < ids.length; i++) { + indexList.push(this.getIndexById(ids[i])); + } + } + $trList.addClass('ew-tree-table-filter-hide'); + for (var j = 0; j < indexList.length; j++) { + var $tr = $trList.filter('[data-index="' + indexList[j] + '"]'); + $tr.removeClass('ew-tree-table-filter-hide'); + var indent = parseInt($tr.data('indent')); + // 联动子级 + $tr.nextAll('tr').each(function () { + if (parseInt($(this).data('indent')) <= indent) return false; + $(this).removeClass('ew-tree-table-filter-hide'); + }); + if ($tr.hasClass('ew-tree-table-open')) toggleRow($tr); + // 联动父级 + $tr.prevAll('tr').each(function () { + var tInd = parseInt($(this).data('indent')); + if (tInd < indent) { + $(this).removeClass('ew-tree-table-filter-hide'); + if (!$(this).hasClass('ew-tree-table-open')) toggleRow($(this)); + indent = tInd; + } + }); + } + // 最后再检查一遍 + /*$trList.not('.ew-tree-table-filter-hide').not('.ew-tree-tb-hide').each(function () { + var index = $(this).data('index'), hide = true; + for (var k = 0; k < indexList.length; k++) { + if (indexList[k] === index) hide = false; + } + if (hide) $(this).addClass('ew-tree-table-filter-hide'); + });*/ + components.$loading.hide(); + components.$loading.removeClass('ew-loading-float'); + if (indexList.length === 0) components.$empty.show(); + updateFixedTbHead(components.$view); // 更新滚动条补丁 + }; + + /** 重置搜索 */ + TreeTable.prototype.clearFilter = function () { + var components = this.getComponents(); + components.$table.children('tbody').children('tr').removeClass('ew-tree-table-filter-hide'); + if (this.options.data.length > 0) components.$empty.hide(); + updateFixedTbHead(components.$view); // 更新滚动条补丁 + }; + + /** + * 刷新指定父级下的节点 + * @param id 父级id,空则全部刷新 + * @param data 非异步模式替换的数据 + */ + TreeTable.prototype.refresh = function (id, data) { + if (isClass(id) === 'Array') { + data = id; + id = undefined; + } + var components = this.getComponents(); + var d, $tr; + if (id !== undefined) { + $tr = components.$table.children('tbody').children('tr[data-index="' + this.getIndexById(id) + '"]'); + d = this.getDataByTr($tr); + } + if (data) { // 数据模式 + if (data.length > 0) components.$loading.addClass('ew-loading-float'); + components.$loading.show(); + if (data.length > 0 && this.options.tree.isPidData) { // pid形式数据 + this.renderBodyData(tt.pidToChildren(data, this.options.tree.idName, this.options.tree.pidName, this.options.tree.childName), d, $tr); + } else { + this.renderBodyData(data, d, $tr); + } + } else { // 异步模式 + this.renderBodyAsync(d, $tr); + } + }; + + /** 删除数据 */ + TreeTable.prototype.del = function (id, index) { + if (index === undefined) index = this.getIndexById(id); + var indexList = (typeof index === 'number' ? [index] : index.split('-')); + var d = this.options.data; + if (indexList.length > 1) { + for (var i = 0; i < indexList.length - 1; i++) { + d = d[parseInt(indexList[i])][this.options.tree.childName]; + } + } + d.splice(indexList[indexList.length - 1], 1); + }; + + /** 更新数据 */ + TreeTable.prototype.update = function (id, fields) { + $.extend(true, this.getDataByTr(this.getIndexById(id)), fields); + }; + + /** 折叠/展开行 */ + function toggleRow($tr) { + var indent = parseInt($tr.data('indent')); + var open = $tr.hasClass('ew-tree-table-open'); + if (open) { // 折叠 + $tr.removeClass('ew-tree-table-open'); + $tr.nextAll('tr').each(function () { + if (parseInt($(this).data('indent')) <= indent) return false; + $(this).addClass('ew-tree-tb-hide'); + }); + } else { // 展开 + $tr.addClass('ew-tree-table-open'); + var hideInd; + $tr.nextAll('tr').each(function () { + var ind = parseInt($(this).data('indent')); + if (ind <= indent) return false; + if (hideInd !== undefined && ind > hideInd) return true; + $(this).removeClass('ew-tree-tb-hide'); + if (!$(this).hasClass('ew-tree-table-open')) hideInd = parseInt($(this).data('indent')); + else hideInd = undefined; + }); + } + updateFixedTbHead($tr.parentsUntil('.ew-tree-table').last().parent()); + return open; + } + + /** 固定表头滚动条补丁 */ + function updateFixedTbHead($view) { + var $headBox = $view.children('.ew-tree-table-head'); + var $tbBox = $view.children('.ew-tree-table-box'); + //修复滚动条出现时,表头宽度不对的问题 + var sWidth = $headBox.width() - $tbBox.prop('clientWidth'); + $headBox.css('border-right', (sWidth > 0 ? sWidth : 0) + 'px solid #f2f2f2'); + } + + // 监听窗口大小改变 + $(window).resize(function () { + $('.ew-tree-table').each(function () { + updateFixedTbHead($(this)); + var $tbBox = $(this).children('.ew-tree-table-box'); + var full = $tbBox.data('full'); + if (full && device.ie && device.ie < 10) { + $tbBox.css('height', getPageHeight() - full); + } + }); + }); + + /** 表格溢出点击展开功能 */ + $(document).on('mouseenter', '.ew-tree-table-cell.single-line', function () { + var $content = $(this).children('.ew-tree-table-cell-content'); + if ($content.prop('scrollWidth') > $content.outerWidth()) $(this).children('.layui-table-grid-down').show(); + }).on('mouseleave', '.ew-tree-table-cell.single-line', function () { + $(this).children('.layui-table-grid-down').hide(); + }); + // 点击箭头展开 + $(document).on('click', '.ew-tree-table-cell>.layui-table-grid-down', function (e) { + e.stopPropagation(); + hideAllTdTips(); + var $cell = $(this).parent(); + $cell.addClass('ew-tree-tips-open'); + $cell.children('.layui-table-grid-down').hide(); + var tw = $cell.parent().outerWidth() + 4; + if ($cell.outerWidth() < tw) $cell.children('.ew-tree-table-cell-content').css({'width': tw, 'max-width': tw}); + var $box = $cell.parents().filter('.ew-tree-table-box'); + if ($box.length === 0) $box = $cell.parents().filter('.ew-tree-table-head'); + if ($box.length === 0) return; + if (($cell.outerWidth() + $cell.offset().left) + 20 > $box.offset().left + $box.outerWidth()) { + $cell.addClass('ew-show-left'); + } + if (($cell.outerHeight() + $cell.offset().top + 10) > $box.offset().top + $box.outerHeight()) { + $cell.addClass('ew-show-bottom'); + } + }); + // 点击关闭按钮关闭 + $(document).on('click', '.ew-tree-table-cell>.ew-tree-tips-c', function () { + hideAllTdTips(); + }); + // 点击空白部分关闭 + $(document).on('click', function () { + hideAllTdTips(); + $('.ew-tree-table .layui-table-tool-panel').remove(); + }); + $(document).on('click', '.ew-tree-table-cell.ew-tree-tips-open', function (e) { + e.stopPropagation(); + }); + + /* 关闭所有单元格溢出提示框 */ + function hideAllTdTips() { + $('.ew-tree-table-cell').removeClass('ew-tree-tips-open ew-show-left ew-show-bottom'); + $('.ew-tree-table-cell>.ew-tree-table-cell-content').css({'width': '', 'max-width': ''}); + } + + /** 拖拽调整列宽 */ + $(document).on('mousedown', '.ew-tb-resize', function (e) { + layui.stope(e); + var $this = $(this); + $this.attr('move', 'true'); + var key = $this.parent().data('key'); + $this.data('x', e.clientX); + var w = $this.parent().parent().parent().parent().children('colgroup').children('col[data-key="' + key + '"]').attr('width'); + if (!w || w.toString().indexOf('%') !== -1) w = $this.parent().outerWidth(); + $this.data('width', w); + $('body').addClass('ew-tree-table-resizing'); + }).on('mousemove', function (e) { + var $rs = $('.ew-tree-table .ew-tb-resize[move="true"]'); + if ($rs.length === 0) return; + layui.stope(e); + var x = $rs.data('x'); + var w = $rs.data('width'); + var nw = parseFloat(w) + e.clientX - parseFloat(x); + if (nw <= 0) nw = 1; + // 更新实例options中的宽度 + var ins = _instances[$rs.parentsUntil('.ew-tree-table').last().parent().attr('lay-filter')]; + var key = $rs.parent().data('key'); + var ks = key.split('-'); + ins.options.cols[ks[0]][ks[1]].width = nw; + ins.eachCols(function (i, item) { + if (item.key === key) item.width = nw; + }); + ins.resize(); + }).on('mouseup', function (e) { + $('.ew-tree-table .ew-tb-resize[move="true"]').attr('move', 'false'); + $('body').removeClass('ew-tree-table-resizing'); + }).on('mouseleave', function (e) { + $('.ew-tree-table .ew-tb-resize[move="true"]').attr('move', 'false'); + $('body').removeClass('ew-tree-table-resizing'); + }); + + /** 获取顶级的pId */ + function getPids(data, idName, pidName) { + var pids = []; + for (var i = 0; i < data.length; i++) { + var hasPid = false; + for (var j = 0; j < data.length; j++) { + if (data[i][pidName] == data[j][idName]) { + hasPid = true; + break; + } + } + if (!hasPid) pids.push(data[i][pidName]); + } + return pids; + } + + /** 判断pId是否相等 */ + function pidEquals(pId, pIds) { + if (isClass(pIds) === 'Array') { + for (var i = 0; i < pIds.length; i++) + if (pId == pIds[i]) return true; + } + return pId == pIds; + } + + /** 获取变量类型 */ + function isClass(o) { + if (o === null) return 'Null'; + if (o === undefined) return 'Undefined'; + return Object.prototype.toString.call(o).slice(8, -1); + } + + /** 获取浏览器高度 */ + function getPageHeight() { + return document.documentElement.clientHeight || document.body.clientHeight; + } + + /** 对外提供的方法 */ + var tt = { + /* 渲染 */ + render: function (options) { + return new TreeTable(options); + }, + /* 重载 */ + reload: function (id, opt) { + _instances[id].reload(opt); + }, + /* 事件监听 */ + on: function (events, callback) { + return layui.onevent.call(this, MOD_NAME, events, callback); + }, + /* pid转children形式 */ + pidToChildren: function (data, idName, pidName, childName, pId) { + if (!childName) childName = 'children'; + var newList = []; + for (var i = 0; i < data.length; i++) { + if (data[i][idName] == data[i][pidName]) + return console.error('第' + i + '条数据的' + idName + '与' + pidName + '相同', data[i]); + if (pId === undefined) pId = getPids(data, idName, pidName); + if (pidEquals(data[i][pidName], pId)) { + var children = this.pidToChildren(data, idName, pidName, childName, data[i][idName]); + if (children.length > 0) data[i][childName] = children; + newList.push(data[i]); + } + } + return newList; + } + }; + + /** 添加样式 */ + $('head').append([ + '' + ].join('')); + + exports('treeTable', tt); +}); diff --git a/ss-admin/src/main/resources/static/js/lay-module/treetable-lay-3.x/treeTable2.js b/ss-admin/src/main/resources/static/js/lay-module/treetable-lay-3.x/treeTable2.js new file mode 100644 index 0000000..17d641d --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/treetable-lay-3.x/treeTable2.js @@ -0,0 +1,2 @@ +/** 树形表格3.x Created by wangfan on 2020-05-12 https://gitee.com/whvse/treetable-lay */ +layui.define(["laytpl","form","util"],function(s){var g=layui.jquery;var d=layui.laytpl;var c=layui.form;var b=layui.util;var o=layui.device();var h="treeTable";var k={};var e={elem:undefined,cols:undefined,url:undefined,method:undefined,where:undefined,contentType:undefined,headers:undefined,parseData:undefined,request:{pidName:"pid"},toolbar:undefined,defaultToolbar:undefined,width:undefined,height:undefined,cellMinWidth:90,done:undefined,data:undefined,title:undefined,skin:undefined,even:undefined,size:undefined,text:{none:"无数据"},reqData:undefined,useAdmin:false,tree:{idName:"id",pidName:"pid",childName:"children",haveChildName:"haveChild",openName:"open",iconIndex:0,arrowType:undefined,onlyIconControl:undefined,getIcon:function(u){var t=u[this.haveChildName];if(t!==undefined){t=t===true||t==="true"}else{if(u[this.childName]){t=u[this.childName].length>0}}if(t){return''}else{return''}}}};var r={field:undefined,title:undefined,width:undefined,minWidth:undefined,type:"normal",fixed:undefined,hide:undefined,unresize:undefined,style:undefined,align:undefined,colspan:undefined,rowspan:undefined,templet:undefined,toolbar:undefined,"class":undefined,singleLine:undefined};var p=function(t){k[t.elem.substring(1)]=this;this.reload(t)};p.prototype.initOptions=function(t){var D=this;function B(J){if(!J.INIT_OK){J=g.extend({INIT_OK:true},r,J)}if(J.type==="space"){if(!J.width){J.width=15}J.minWidth=J.width}else{if(J.type==="numbers"){if(!J.width){J.width=40}J.minWidth=J.width;if(!J.singleLine){J.singleLine=false}if(!J.unresize){J.unresize=true}if(!J.align){J.align="center"}}else{if(J.type==="checkbox"||J.type==="radio"){if(!J.width){J.width=48}J.minWidth=J.width;if(!J.singleLine){J.singleLine=false}if(!J.unresize){J.unresize=true}if(!J.align){J.align="center"}}}}if(J.toolbar){J.type="tool"}return J}if("Array"!==l(t.cols[0])){t.cols=[t.cols]}for(var w=0;w1){A.colGroup=true;A.type="group";I=[];G++;var z=0;for(var v=0;v1&&z==A.colspan)){t.cols[y+1][v]=H;continue}H.HAS_PARENT=true;H.parentKey=y+"-"+x;H.key=(y+1)+"-"+v;H.PARENT_COL_INDEX=G;H=B(H);I.push(H);z=z+parseInt(H.colspan>1?H.colspan:1);t.cols[y+1][v]=H}}A.CHILD_COLS=I;if(!A.PARENT_COL_INDEX){F.push(A)}t.cols[y][x]=A}}this.options=g.extend(true,{},e,t);this.options.colArrays=F;if(this.options.url){this.options.reqData=function(J,K){if(!D.options.where){D.options.where={}}if(J){D.options.where[D.options.request.pidName]=J[D.options.tree.idName]}(D.options.useAdmin?layui.admin:g).ajax({url:D.options.url,data:D.options.contentType&&D.options.contentType.indexOf("application/json")===0?JSON.stringify(D.options.where):D.options.where,headers:D.options.headers,type:D.options.method,dataType:"json",contentType:D.options.contentType,success:function(L){if(D.options.parseData){L=D.options.parseData(L)}if(L.code==0){K(L.data)}else{K(L.msg||"加载失败")}},error:function(L){K(L.status+" - "+L.statusText)}})}}else{if(this.options.data&&this.options.data.length>0&&this.options.tree.isPidData){this.options.data=a.pidToChildren(this.options.data,this.options.tree.idName,this.options.tree.pidName,this.options.tree.childName)}}if("default"===this.options.toolbar){this.options.toolbar=["
    ",'
    ',' ',"
    ",'
    ',' ',"
    ",'
    ',' ',"
    ","
    "].join("")}if(this.options.defaultToolbar===undefined){this.options.defaultToolbar=["filter","exports","print"]}if(typeof this.options.tree.getIcon==="string"){var E=this.options.tree.getIcon;this.options.tree.getIcon=function(K){if(E!=="ew-tree-icon-style2"){return E}var J=K[this.haveChildName];if(J!==undefined){J=J===true||J==="true"}else{if(K[this.childName]){J=K[this.childName].length>0}}if(J){return''}else{return''}}}};p.prototype.init=function(){var E=this.options;var u=g(E.elem);var B=E.elem.substring(1);u.removeAttr("lay-filter");if(u.next(".ew-tree-table").length===0){u.css("display","none");u.after(['
    ',' ','
    ','
    ',"
    ",'
    ','
    ','
    ',' ',"
    ",'
    ',E.text.none||"","
    ","
    ","
    "].join(""))}var A=this.getComponents();if(E.skin){A.$table.attr("lay-skin",E.skin)}if(E.size){A.$table.attr("lay-size",E.size)}if(E.even){A.$table.attr("lay-even",E.even)}A.$toolbar.empty();if(E.toolbar===false||E.toolbar===undefined){A.$toolbar.hide()}else{A.$toolbar.show();if(typeof E.toolbar==="string"){d(g(E.toolbar).html()).render({},function(F){A.$toolbar.html('
    '+F+"
    ")})}var C=['
    '];for(var y=0;y');C.push('
    ')}}A.$toolbar.append(C.join("")+"")}if(E.width){A.$view.css("width",E.width);A.$tHeadGroup.css("width",E.width);A.$tBodyGroup.css("width",E.width)}var v=this.resize(true);var D=""+this.renderBodyTh()+"";A.$tBodyGroup.children("style").remove();if(E.height){A.$tHead.html(v+D);A.$tBody.html(v+"");if(E.height.indexOf("full-")===0){var z=parseFloat(E.height.substring(5))+A.$toolbar.outerHeight()+A.$tHeadGroup.outerHeight()+1;A.$tBodyGroup.append(['"].join(""));A.$tBodyGroup.data("full",z);A.$tBodyGroup.css("height","")}else{A.$tBodyGroup.css("height",E.height);A.$tBodyGroup.data("full","")}A.$tHeadGroup.show()}else{A.$tHeadGroup.hide();var x={lg:50,sm:30,md:38};A.$tBodyGroup.append(['"].join(""));A.$tBody.html(v+D+"")}c.render("checkbox",B);function t(H){var F=H.data("parent"),G;if(!F){return}var I=A.$table.children("thead").children("tr").children('[data-key="'+F+'"]');var J=I.attr("colspan")-1;I.attr("colspan",J);if(J===0){I.addClass("layui-hide")}t(I)}A.$table.children("thead").children("tr").children("th.layui-hide").each(function(){t(g(this))});if(E.reqData){this.options.data=undefined;this.renderBodyAsync()}else{if(E.data&&E.data.length>0){this.renderBodyData(E.data)}else{A.$loading.hide();A.$empty.show()}}};p.prototype.bindEvents=function(){var v=this;var t=this.options;var u=this.getComponents();var w=u.$table.children("tbody");var x=function(y){var z=g(this);if(!z.is("tr")){var C=z.parent("tr");if(C.length>0){z=C}else{z=z.parentsUntil("tr").last().parent()}}var A=v.getDataByTr(z);var B={tr:z,data:A,del:function(){var F=z.data("index");var D=parseInt(z.data("indent"));z.nextAll("tr").each(function(){if(parseInt(g(this).data("indent"))<=D){return false}g(this).remove()});var G=(typeof F==="number"?1:F.split("-").length);z.nextAll("tr").each(function(){var H=g(this);if(parseInt(H.data("indent"))=D){return true}v.checkParentCB(g(this));D=H});v.checkChooseAllCB();if(t.data.length===0){u.$empty.show()}f(u.$view)},update:function(E){A=g.extend(true,A,E);var D=parseInt(z.data("indent"));v.renderBodyTr(A,D,undefined,z);c.render(null,u.filter);v.renderNumberCol();z.prevAll("tr").each(function(){var F=parseInt(g(this).data("indent"));if(F>=D){return true}v.checkParentCB(g(this));D=F});v.checkChooseAllCB()}};return g.extend(B,y)};w.off("click.fold").on("click.fold",".ew-tree-pack",function(C){layui.stope(C);var A=g(this).parentsUntil("tr").last().parent();if(A.hasClass("ew-tree-table-loading")){return}var y=A.data("have-child");if(y!==true&&y!=="true"){return}var z=A.hasClass("ew-tree-table-open");var B=v.getDataByTr(A);if(!z&&!B[t.tree.childName]){v.renderBodyAsync(B,A)}else{B[t.tree.openName]=i(A)}});w.off("click.tool").on("click.tool","*[lay-event]",function(z){layui.stope(z);var y=g(this);layui.event.call(this,h,"tool("+u.filter+")",x.call(this,{event:y.attr("lay-event")}))});c.on("radio("+u.radioFilter+")",function(y){var z=v.getDataByTr(g(y.elem).parentsUntil("tr").last().parent());v.removeAllChecked();z.LAY_CHECKED=true;z.LAY_INDETERMINATE=false;layui.event.call(this,h,"checkbox("+u.filter+")",{checked:true,data:z,type:"one"})});c.on("checkbox("+u.checkboxFilter+")",function(C){var B=C.elem.checked;var E=g(C.elem);var z=E.next(".layui-form-checkbox");if(!B&&E.hasClass("ew-form-indeterminate")){B=true;E.prop("checked",B);z.addClass("layui-form-checked");E.removeClass("ew-form-indeterminate")}var A=E.parentsUntil("tr").last().parent();var D=v.getDataByTr(A);D.LAY_CHECKED=B;D.LAY_INDETERMINATE=false;if(D[t.tree.childName]&&D[t.tree.childName].length>0){v.checkSubCB(A,B)}var y=parseInt(A.data("indent"));A.prevAll("tr").each(function(){var F=parseInt(g(this).data("indent"));if(F0){return}var B=y.data("index");var z=y.find(".ew-tree-table-indent").length;var D=v.getDataByTr(y.parent());if("text"===H||"number"===H){var F=g('');F[0].value=D[G];y.append(F);F.focus();F.blur(function(){var K=g(this).val();if(K==D[G]){return g(this).remove()}var I=layui.event.call(this,h,"edit("+u.filter+")",x.call(this,{value:K,field:G}));if(I===false){g(this).addClass("layui-form-danger");g(this).focus()}else{D[G]=K;var J=y.data("key").split("-");v.renderBodyTd(D,z,B,y,t.cols[J[0]][J[1]])}})}else{console.error("不支持的单元格编辑类型:"+H)}}else{var A=layui.event.call(this,h,"cell("+u.filter+")",x.call(this,{td:y,field:G}));if(A===false){layui.stope(C)}}});w.off("dblclick.cellDouble").on("dblclick.cellDouble","td",function(C){var D=g(this);var z=D.data("type");if(z==="checkbox"||z==="radio"){return layui.stope(C)}var A=D.data("edit");var B=D.data("field");if(A){return layui.stope(C)}var y=layui.event.call(this,h,"cellDouble("+u.filter+")",x.call(this,{td:D,field:B}));if(y===false){layui.stope(C)}});u.$toolbar.off("click.toolbar").on("click.toolbar","*[lay-event]",function(A){layui.stope(A);var z=g(this);var y=z.attr("lay-event");if("LAYTABLE_COLS"===y){v.toggleCol()}else{if("LAYTABLE_EXPORT"===y){v.exportData("show")}else{if("LAYTABLE_PRINT"===y){v.printTable()}else{layui.event.call(this,h,"toolbar("+u.filter+")",{event:y,elem:z})}}}});u.$tBodyGroup.on("scroll",function(){var y=g(this);u.$tHeadGroup.scrollLeft(y.scrollLeft())});u.$toolbar.off("click.export").on("click.export",".layui-table-tool-panel>[data-type]",function(){var y=g(this).data("type");if("csv"===y||"xls"===y){v.exportData(y)}});u.$toolbar.off("click.panel").on("click.panel",".layui-table-tool-panel",function(y){layui.stope(y)});c.on("checkbox("+u.colsToggleFilter+")",function(y){v.toggleCol(y.elem.checked,undefined,y.value)})};p.prototype.getComponents=function(){var v=g(this.options.elem).next(".ew-tree-table");var t=v.attr("lay-filter");var w=v.children(".ew-tree-table-head");var u=v.children(".ew-tree-table-box");return{$view:v,filter:t,$tHeadGroup:w,$tBodyGroup:u,$tHead:w.children(".layui-table"),$tBody:u.children(".layui-table"),$table:v.find(".layui-table"),$toolbar:v.children(".ew-tree-table-tool"),$empty:u.children(".ew-tree-table-empty"),$loading:u.children(".ew-tree-table-loading"),checkboxFilter:"ew_tb_checkbox_"+t,radioFilter:"ew_tb_radio_"+t,chooseAllFilter:"ew_tb_choose_all_"+t,colsToggleFilter:"ew_tb_toggle_cols"+t}};p.prototype.eachCols=function(w,v){if(!v){v=this.options.colArrays}for(var t=0;t0){u.$loading.addClass("ew-loading-float")}u.$loading.show()}t.reqData(x,function(y){if(typeof y!=="string"&&y&&y.length>0&&t.tree.isPidData){y=a.pidToChildren(y,t.tree.idName,t.tree.pidName,t.tree.childName)}v.renderBodyData(y,x,w)})};p.prototype.renderBodyData=function(w,A,x){var u;if(typeof w==="string"){u=w;w=[]}var z=this;var C=this.options;var y=this.getComponents();if(A===undefined){C.data=w}else{A[C.tree.childName]=w}var v;if(x){v=parseInt(x.data("indent"))+1;A[C.tree.openName]=true}var t=this.renderBody(w,v,A);if(x){x.nextAll("tr").each(function(){if(parseInt(g(this).data("indent"))<=(v-1)){return false}g(this).remove()});x.after(t).addClass("ew-tree-table-open")}else{y.$tBody.children("tbody").html(t)}c.render(null,y.filter);this.renderNumberCol();if(x){this.checkParentCB(x);x.prevAll("tr").each(function(){var D=parseInt(g(this).data("indent"));if(D<(v-1)){z.checkParentCB(g(this));v=D+1}});x.removeClass("ew-tree-table-loading");var B=x.find(".ew-tree-pack").children(".ew-tree-table-arrow");B.removeClass("layui-anim layui-anim-rotate layui-anim-loop");if(u){x.removeClass("ew-tree-table-open")}else{if(w&&w.length===0){A[C.tree.haveChildName]=false;x.data("have-child",false);B.addClass("ew-tree-table-arrow-hide");B.next(".ew-tree-icon").after(C.tree.getIcon(A)).remove()}}}else{y.$loading.hide();y.$loading.removeClass("ew-loading-float");if(w&&w.length>0){y.$empty.hide()}else{y.$empty.show();if(u){y.$empty.text(u)}else{y.$empty.html(C.text.none)}}}this.checkChooseAllCB();f(y.$view);C.done&&C.done(w)};p.prototype.renderBody=function(z,t,y){var u=this.options;if(!t){t=0}var x="";if(!z||z.length===0){return x}var w=y?!y[u.tree.openName]:undefined;for(var v=0;v0}if(w){w.data("have-child",A?"true":"false");w.data("indent",u);w.removeClass("ew-tree-table-loading")}var v="');var y=0;this.eachCols(function(E,D){if(D.colGroup){return}v+=z.renderBodyTd(B,u,y,w?w.children("td").eq(y):undefined,D);y++});v+="";return v};p.prototype.renderBodyTd=function(C,v,A,t,u){if(u.colGroup){return""}var F=this.options;var y=this.getComponents();if(!v){v=0}var B="",E="",D="";if(u.type==="numbers"){B=''}else{if(u.type==="checkbox"){B=[''].join("")}else{if(u.type==="radio"){B=[''].join("")}else{if(u.templet){if(typeof u.templet==="function"){B=u.templet(C)}else{if(typeof u.templet==="string"){d(g(u.templet).html()).render(C,function(G){B=G})}}}else{if(u.toolbar){if(typeof u.toolbar==="function"){B=u.toolbar(C)}else{if(typeof u.toolbar==="string"){d(g(u.toolbar).html()).render(C,function(G){B=G})}}}else{if(u.field&&C[u.field]!==undefined&&C[u.field]!==null){B=b.escape(C[u.field]===0?"0":C[u.field])}}}}}}if(A===F.tree.iconIndex){for(var w=0;w'}D+='';var z=C[F.tree.haveChildName];if(z===undefined){z=C[F.tree.childName]&&C[F.tree.childName].length>0}D+=('');D+=F.tree.getIcon(C);B=""+B+"";if(F.tree.onlyIconControl){B=D+""+B}else{B=D+B+""}}E=['
    ",'
    ',B,"
    ",' ',' ',"
    "].join("");if(t){t.html(E)}var x=""+E+"");return x};p.prototype.renderBodyTh=function(){var t=this.options;var v=this.getComponents();var u=[];g.each(t.cols,function(x,w){u.push("");g.each(w,function(A,z){u.push("");u.push('
    ");u.push('
    ');var y='';if(z.type==="checkbox"){u.push(y)}else{u.push(z.title||"")}u.push('
    ');u.push('
    ');if(!z.colGroup&&!z.unresize){u.push('')}u.push("")});u.push("")});return u.join("")};p.prototype.resize=function(z){var t=this.options;var x=this.getComponents();var v=1,u=1,A=true,w=0;this.eachCols(function(B,C){if(C.colGroup||C.hide){return}if(C.width){u+=(C.width+1);if(C.minWidth){if(C.width")});y=y.join("");if(z){return""+y+""}x.$table.children("colgroup").html(y)};p.prototype.getDataByTr=function(v){var w,t;if(typeof v!=="string"&&typeof v!=="number"){if(v){t=v.data("index")}}else{t=v}if(t===undefined){return}if(typeof t==="number"){t=[t]}else{t=t.split("-")}for(var u=0;u0&&v===0){A.prop("checked",true);A.removeClass("ew-form-indeterminate");A.next(".layui-form-checkbox").addClass("layui-form-checked");z.LAY_CHECKED=true;z.LAY_INDETERMINATE=false}else{if(y===0&&v>0){A.prop("checked",false);A.removeClass("ew-form-indeterminate");A.next(".layui-form-checkbox").removeClass("layui-form-checked");z.LAY_CHECKED=false;z.LAY_INDETERMINATE=false}else{if(y>0&&v>0){A.prop("checked",true);A.data("indeterminate","true");A.addClass("ew-form-indeterminate");A.next(".layui-form-checkbox").addClass("layui-form-checked");z.LAY_CHECKED=true;z.LAY_INDETERMINATE=true}}}};p.prototype.checkChooseAllCB=function(){var u=this.options;var w=this.getComponents();var x=0,v=0;function t(A){for(var z=0;z0&&v===0){y.prop("checked",true);y.removeClass("ew-form-indeterminate");y.next(".layui-form-checkbox").addClass("layui-form-checked")}else{if((x===0&&v>0)||(x===0&&v===0)){y.prop("checked",false);y.removeClass("ew-form-indeterminate");y.next(".layui-form-checkbox").removeClass("layui-form-checked")}else{if(x>0&&v>0){y.prop("checked",true);y.addClass("ew-form-indeterminate");y.next(".layui-form-checkbox").addClass("layui-form-checked")}}}};p.prototype.renderNumberCol=function(){this.getComponents().$tBody.children("tbody").children("tr").each(function(t){g(this).children("td").find(".ew-tree-table-numbers").text(t+1)})};p.prototype.getIndexById=function(v){var t=this.options;function u(x,y){for(var w=0;w0){t.each(function(){var x=w.getDataByTr(g(this).parentsUntil("tr").parent());if(x&&u[u.length-1]==x[w.options.tree.idName]){g(this).next(".layui-form-radio").trigger("click");return false}})}else{v.$table.find('input[lay-filter="'+v.checkboxFilter+'"]').each(function(){var C=g(this);var y=C.next(".layui-form-checkbox");var z=C.prop("checked");var B=C.hasClass("ew-form-indeterminate");var A=w.getDataByTr(C.parentsUntil("tr").parent());for(var x=0;x0){continue}if(!z||B){y.trigger("click")}}}})}};p.prototype.removeAllChecked=function(){this.checkSubCB(this.getComponents().$table.children("tbody"),false)};p.prototype.exportData=function(w){var y=this.getComponents();if("show"===w){y.$toolbar.find(".layui-table-tool-panel").remove();y.$toolbar.find('[lay-event="LAYTABLE_EXPORT"]').append(['
      ','
    • 导出到 Csv 文件
    • ','
    • 导出到 Excel 文件
    • ',"
    "].join(""))}else{if(o.ie){return layer.msg("不支持ie导出")}if(!w){w="xls"}var u=[],t=[];this.eachCols(function(A,B){if(B.type!=="normal"||B.hide){return}u.push(B.title||"")});y.$tBody.children("tbody").children("tr").each(function(){var A=[];g(this).children("td").each(function(){var B=g(this);if(B.data("type")!=="normal"||B.hasClass("layui-hide")){return true}A.push(B.text().trim().replace(/,/g,","))});t.push(A.join(","))});var v=document.createElement("a");var x=encodeURIComponent(u.join(",")+"\r\n"+t.join("\r\n"));var z=({csv:"text/csv",xls:"application/vnd.ms-excel"})[w];v.href="data:"+z+";charset=utf-8,\ufeff"+x;v.download=(this.options.title||"table")+"."+w;document.body.appendChild(v);v.click();document.body.removeChild(v)}};p.prototype.printTable=function(){var w=this.getComponents();var z=w.$tHead.children("thead").html();if(!z){z=w.$tBody.children("thead").html()}var x=w.$tBody.children("tbody").html();var v=w.$tBody.children("colgroup").html();var u=g([''," ",v,""," ",z,""," ",x,"","
    "].join(""));u.find('col[data-type="checkbox"],col[data-type="radio"],col[data-type="tool"]').remove();u.find('td[data-type="checkbox"],td[data-type="radio"],td[data-type="tool"],.layui-hide').remove();function A(F){var C=F.data("parent"),D;if(!C){return}var E=u.children("thead").children("tr").children('[data-key="'+C+'"]');var G=parseInt(E.attr("colspan"))-1;E.attr("colspan",G);if(G===0){E.remove()}A(E)}u.find('th[data-type="checkbox"],th[data-type="radio"],th[data-type="tool"]').each(function(){A(g(this))}).remove();var t=[""].join("");var y=window.open("","_blank");y.focus();var B=y.document;B.open();B.write(u[0].outerHTML+t);B.close();y.print();y.close()};p.prototype.toggleCol=function(A,z,B){var w=this.getComponents();if(A===undefined){w.$toolbar.find(".layui-table-tool-panel").remove();var x=['
      '];this.eachCols(function(D,E){if(E.type!=="normal"){return}x.push('
    • ")});w.$toolbar.find('[lay-event="LAYTABLE_COLS"]').append(x.join("")+"
    ");c.render("checkbox",w.filter)}else{if(B){var u=w.$table.children("tbody").children("tr").children('[data-key="'+B+'"]');var C=w.$table.children("thead").children("tr").children('[data-key="'+B+'"]');if(A){u.removeClass("layui-hide");C.removeClass("layui-hide")}else{u.addClass("layui-hide");C.addClass("layui-hide")}var y=B.split("-");var v=this.options.cols[y[0]][y[1]];v.hide=!A;function t(G){var D=G.data("parent"),E;if(!D){return}var F=w.$table.children("thead").children("tr").children('[data-key="'+D+'"]');var H=F.attr("colspan");A?H++:H--;F.attr("colspan",H);if(H===0){F.addClass("layui-hide")}else{F.removeClass("layui-hide")}t(F)}t(C);this.eachCols(function(D,E){if(E.key===B){E.hide=v.hide}});this.resize()}}};p.prototype.filterData=function(y){var A=this.getComponents();A.$loading.show();if(this.options.data.length>0){A.$loading.addClass("ew-loading-float")}var x=A.$table.children("tbody").children("tr");var u=[];if(typeof y==="string"){x.each(function(){var B=g(this).data("index");g(this).children("td").each(function(){if(g(this).text().indexOf(y)!==-1){u.push(B);return false}})})}else{for(var w=0;w0){t.$empty.hide()}f(t.$view)};p.prototype.refresh=function(x,v){if(l(x)==="Array"){v=x;x=undefined}var u=this.getComponents();var w,t;if(x!==undefined){t=u.$table.children("tbody").children('tr[data-index="'+this.getIndexById(x)+'"]');w=this.getDataByTr(t)}if(v){if(this.data.length>0){u.$loading.addClass("ew-loading-float")}u.$loading.show();if(v.length>0&&this.options.tree.isPidData){this.renderBodyData(a.pidToChildren(v,this.options.tree.idName,this.options.tree.pidName,this.options.tree.childName),w,t)}else{this.renderBodyData(v,w,t)}}else{this.renderBodyAsync(w,t)}};p.prototype.del=function(x,u){if(u===undefined){u=this.getIndexById(x)}var t=(typeof u==="number"?[u]:u.split("-"));var w=this.options.data;if(t.length>1){for(var v=0;vw){return true}g(this).removeClass("ew-tree-tb-hide");if(!g(this).hasClass("ew-tree-table-open")){w=parseInt(g(this).data("indent"))}else{w=undefined}})}f(v.parentsUntil(".ew-tree-table").last().parent());return u}function f(w){var t=w.children(".ew-tree-table-head");var u=w.children(".ew-tree-table-box");var v=u.width()-u.prop("clientWidth");t.css("border-right",(v>0?v:0)+"px solid #f2f2f2")}g(window).resize(function(){g(".ew-tree-table").each(function(){f(g(this));var u=g(this).children(".ew-tree-table-box");var t=u.data("full");if(t&&o.ie&&o.ie<10){u.css("height",m()-t)}})});g(document).on("mouseenter",".ew-tree-table-cell.single-line",function(){var t=g(this).children(".ew-tree-table-cell-content");if(t.prop("scrollWidth")>t.outerWidth()){g(this).children(".layui-table-grid-down").show()}}).on("mouseleave",".ew-tree-table-cell.single-line",function(){g(this).children(".layui-table-grid-down").hide()});g(document).on("click",".ew-tree-table-cell>.layui-table-grid-down",function(w){w.stopPropagation();j();var u=g(this).parent();u.addClass("ew-tree-tips-open");u.children(".layui-table-grid-down").hide();var t=u.parent().outerWidth()+4;if(u.outerWidth()v.offset().left+v.outerWidth()){u.addClass("ew-show-left")}if((u.outerHeight()+u.offset().top+10)>v.offset().top+v.outerHeight()){u.addClass("ew-show-bottom")}});g(document).on("click",".ew-tree-table-cell>.ew-tree-tips-c",function(){j()});g(document).on("click",function(){j();g(".ew-tree-table .layui-table-tool-panel").remove()});g(document).on("click",".ew-tree-table-cell.ew-tree-tips-open",function(t){t.stopPropagation()});function j(){g(".ew-tree-table-cell").removeClass("ew-tree-tips-open ew-show-left ew-show-bottom");g(".ew-tree-table-cell>.ew-tree-table-cell-content").css({"width":"","max-width":""})}g(document).on("mousedown",".ew-tb-resize",function(x){layui.stope(x);var v=g(this);v.attr("move","true");var u=v.parent().data("key");v.data("x",x.clientX);var t=v.parent().parent().parent().parent().children("colgroup").children('col[data-key="'+u+'"]').attr("width");if(!t||t.toString().indexOf("%")!==-1){t=v.parent().outerWidth()}v.data("width",t);g("body").addClass("ew-tree-table-resizing")}).on("mousemove",function(B){var y=g('.ew-tree-table .ew-tb-resize[move="true"]');if(y.length===0){return}layui.stope(B);var t=y.data("x");var v=y.data("width");var u=parseFloat(v)+B.clientX-parseFloat(t);if(u<=0){u=1}var z=k[y.parentsUntil(".ew-tree-table").last().parent().attr("lay-filter")];var A=y.parent().data("key");var C=A.split("-");z.options.cols[C[0]][C[1]].width=u;z.eachCols(function(w,x){if(x.key===A){x.width=u}});z.resize()}).on("mouseup",function(t){g('.ew-tree-table .ew-tb-resize[move="true"]').attr("move","false");g("body").removeClass("ew-tree-table-resizing")}).on("mouseleave",function(t){g('.ew-tree-table .ew-tb-resize[move="true"]').attr("move","false");g("body").removeClass("ew-tree-table-resizing")});function q(x,u,z){var y=[];for(var w=0;w0){z[w][t]=v}y.push(z[w])}}return y}};g("head").append(['"].join(""));s("treeTable",a)}); \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/js/lay-module/treetable-lay/treetable.css b/ss-admin/src/main/resources/static/js/lay-module/treetable-lay/treetable.css new file mode 100644 index 0000000..584b2f8 --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/treetable-lay/treetable.css @@ -0,0 +1,18 @@ +.treeTable-empty { + width: 20px; + display: inline-block; +} + +.treeTable-icon { + cursor: pointer; +} + +.treeTable-icon .layui-icon-triangle-d:before { + content: "\e623"; +} + +.treeTable-icon.open .layui-icon-triangle-d:before { + content: "\e625"; + background-color: transparent; +} + diff --git a/ss-admin/src/main/resources/static/js/lay-module/treetable-lay/treetable.js b/ss-admin/src/main/resources/static/js/lay-module/treetable-lay/treetable.js new file mode 100644 index 0000000..e38a5e1 --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/treetable-lay/treetable.js @@ -0,0 +1,206 @@ +layui.define(['layer', 'table'], function (exports) { + var $ = layui.jquery; + var layer = layui.layer; + var table = layui.table; + + var treetable = { + // 渲染树形表格 + render: function (param) { + // 检查参数 + if (!treetable.checkParam(param)) { + return; + } + // 获取数据 + if (param.data) { + treetable.init(param, param.data); + } else { + $.getJSON(param.url, param.where, function (res) { + treetable.init(param, res.data); + }); + } + }, + // 渲染表格 + init: function (param, data) { + var mData = []; + var doneCallback = param.done; + var tNodes = data; + // 补上id和pid字段 + for (var i = 0; i < tNodes.length; i++) { + var tt = tNodes[i]; + if (!tt.id) { + if (!param.treeIdName) { + layer.msg('参数treeIdName不能为空', {icon: 5}); + return; + } + tt.id = tt[param.treeIdName]; + } + if (!tt.pid) { + if (!param.treePidName) { + layer.msg('参数treePidName不能为空', {icon: 5}); + return; + } + tt.pid = tt[param.treePidName]; + } + } + + // 对数据进行排序 + var sort = function (s_pid, data) { + for (var i = 0; i < data.length; i++) { + if (data[i].pid == s_pid) { + var len = mData.length; + if (len > 0 && mData[len - 1].id == s_pid) { + mData[len - 1].isParent = true; + } + mData.push(data[i]); + sort(data[i].id, data); + } + } + }; + sort(param.treeSpid, tNodes); + + // 重写参数 + param.url = undefined; + param.data = mData; + param.page = { + count: param.data.length, + limit: param.data.length + }; + param.cols[0][param.treeColIndex].templet = function (d) { + var mId = d.id; + var mPid = d.pid; + var isDir = d.isParent; + var emptyNum = treetable.getEmptyNum(mPid, mData); + var iconHtml = ''; + for (var i = 0; i < emptyNum; i++) { + iconHtml += ''; + } + if (isDir) { + iconHtml += ' '; + } else { + iconHtml += ''; + } + iconHtml += '  '; + var ttype = isDir ? 'dir' : 'file'; + var vg = ''; + return vg + iconHtml + d[param.cols[0][param.treeColIndex].field] + '' + }; + + param.done = function (res, curr, count) { + $(param.elem).next().addClass('treeTable'); + $('.treeTable .layui-table-page').css('display', 'none'); + $(param.elem).next().attr('treeLinkage', param.treeLinkage); + // 绑定事件换成对body绑定 + /*$('.treeTable .treeTable-icon').click(function () { + treetable.toggleRows($(this), param.treeLinkage); + });*/ + if (param.treeDefaultClose) { + treetable.foldAll(param.elem); + } + if (doneCallback) { + doneCallback(res, curr, count); + } + }; + + // 渲染表格 + table.render(param); + }, + // 计算缩进的数量 + getEmptyNum: function (pid, data) { + var num = 0; + if (!pid) { + return num; + } + var tPid; + for (var i = 0; i < data.length; i++) { + if (pid == data[i].id) { + num += 1; + tPid = data[i].pid; + break; + } + } + return num + treetable.getEmptyNum(tPid, data); + }, + // 展开/折叠行 + toggleRows: function ($dom, linkage) { + var type = $dom.attr('lay-ttype'); + if ('file' == type) { + return; + } + var mId = $dom.attr('lay-tid'); + var isOpen = $dom.hasClass('open'); + if (isOpen) { + $dom.removeClass('open'); + } else { + $dom.addClass('open'); + } + $dom.closest('tbody').find('tr').each(function () { + var $ti = $(this).find('.treeTable-icon'); + var pid = $ti.attr('lay-tpid'); + var ttype = $ti.attr('lay-ttype'); + var tOpen = $ti.hasClass('open'); + if (mId == pid) { + if (isOpen) { + $(this).hide(); + if ('dir' == ttype && tOpen == isOpen) { + $ti.trigger('click'); + } + } else { + $(this).show(); + if (linkage && 'dir' == ttype && tOpen == isOpen) { + $ti.trigger('click'); + } + } + } + }); + }, + // 检查参数 + checkParam: function (param) { + if (!param.treeSpid && param.treeSpid != 0) { + layer.msg('参数treeSpid不能为空', {icon: 5}); + return false; + } + + if (!param.treeColIndex && param.treeColIndex != 0) { + layer.msg('参数treeColIndex不能为空', {icon: 5}); + return false; + } + return true; + }, + // 展开所有 + expandAll: function (dom) { + $(dom).next('.treeTable').find('.layui-table-body tbody tr').each(function () { + var $ti = $(this).find('.treeTable-icon'); + var ttype = $ti.attr('lay-ttype'); + var tOpen = $ti.hasClass('open'); + if ('dir' == ttype && !tOpen) { + $ti.trigger('click'); + } + }); + }, + // 折叠所有 + foldAll: function (dom) { + $(dom).next('.treeTable').find('.layui-table-body tbody tr').each(function () { + var $ti = $(this).find('.treeTable-icon'); + var ttype = $ti.attr('lay-ttype'); + var tOpen = $ti.hasClass('open'); + if ('dir' == ttype && tOpen) { + $ti.trigger('click'); + } + }); + } + }; + + layui.link(layui.cache.base + 'treetable-lay/treetable.css'); + + // 给图标列绑定事件 + $('body').on('click', '.treeTable .treeTable-icon', function () { + var treeLinkage = $(this).parents('.treeTable').attr('treeLinkage'); + if ('true' == treeLinkage) { + treetable.toggleRows($(this), true); + } else { + treetable.toggleRows($(this), false); + } + }); + + exports('treetable', treetable); +}); diff --git a/ss-admin/src/main/resources/static/js/lay-module/wangEditor/fonts/w-e-icon.woff b/ss-admin/src/main/resources/static/js/lay-module/wangEditor/fonts/w-e-icon.woff new file mode 100644 index 0000000..6dc5b5a Binary files /dev/null and b/ss-admin/src/main/resources/static/js/lay-module/wangEditor/fonts/w-e-icon.woff differ diff --git a/ss-admin/src/main/resources/static/js/lay-module/wangEditor/wangEditor.css b/ss-admin/src/main/resources/static/js/lay-module/wangEditor/wangEditor.css new file mode 100644 index 0000000..5502c55 --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/wangEditor/wangEditor.css @@ -0,0 +1,411 @@ +.w-e-toolbar, +.w-e-text-container, +.w-e-menu-panel { + padding: 0; + margin: 0; + box-sizing: border-box; +} +.w-e-toolbar *, +.w-e-text-container *, +.w-e-menu-panel * { + padding: 0; + margin: 0; + box-sizing: border-box; +} +.w-e-clear-fix:after { + content: ""; + display: table; + clear: both; +} + +.w-e-toolbar .w-e-droplist { + position: absolute; + left: 0; + top: 0; + background-color: #fff; + border: 1px solid #f1f1f1; + border-right-color: #ccc; + border-bottom-color: #ccc; +} +.w-e-toolbar .w-e-droplist .w-e-dp-title { + text-align: center; + color: #999; + line-height: 2; + border-bottom: 1px solid #f1f1f1; + font-size: 13px; +} +.w-e-toolbar .w-e-droplist ul.w-e-list { + list-style: none; + line-height: 1; +} +.w-e-toolbar .w-e-droplist ul.w-e-list li.w-e-item { + color: #333; + padding: 5px 0; +} +.w-e-toolbar .w-e-droplist ul.w-e-list li.w-e-item:hover { + background-color: #f1f1f1; +} +.w-e-toolbar .w-e-droplist ul.w-e-block { + list-style: none; + text-align: left; + padding: 5px; +} +.w-e-toolbar .w-e-droplist ul.w-e-block li.w-e-item { + display: inline-block; + *display: inline; + *zoom: 1; + padding: 3px 5px; +} +.w-e-toolbar .w-e-droplist ul.w-e-block li.w-e-item:hover { + background-color: #f1f1f1; +} + +@font-face { + font-family: 'w-e-icon'; + src: url(data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAABhQAAsAAAAAGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABCAAAAGAAAABgDxIPBGNtYXAAAAFoAAABBAAAAQQrSf4BZ2FzcAAAAmwAAAAIAAAACAAAABBnbHlmAAACdAAAEvAAABLwfpUWUWhlYWQAABVkAAAANgAAADYQp00kaGhlYQAAFZwAAAAkAAAAJAfEA+FobXR4AAAVwAAAAIQAAACEeAcD7GxvY2EAABZEAAAARAAAAERBSEX+bWF4cAAAFogAAAAgAAAAIAAsALZuYW1lAAAWqAAAAYYAAAGGmUoJ+3Bvc3QAABgwAAAAIAAAACAAAwAAAAMD3gGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAA8fwDwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEAOgAAAA2ACAABAAWAAEAIOkG6Q3pEulH6Wbpd+m56bvpxunL6d/qDepc6l/qZepo6nHqefAN8BTxIPHc8fz//f//AAAAAAAg6QbpDekS6UfpZel36bnpu+nG6cvp3+oN6lzqX+pi6mjqcep38A3wFPEg8dzx/P/9//8AAf/jFv4W+Bb0FsAWoxaTFlIWURZHFkMWMBYDFbUVsxWxFa8VpxWiEA8QCQ7+DkMOJAADAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAACAAD/wAQAA8AABAATAAABNwEnAQMuAScTNwEjAQMlATUBBwGAgAHAQP5Anxc7MmOAAYDA/oDAAoABgP6ATgFAQAHAQP5A/p0yOxcBEU4BgP6A/YDAAYDA/oCAAAQAAAAABAADgAAQACEALQA0AAABOAExETgBMSE4ATEROAExITUhIgYVERQWMyEyNjURNCYjBxQGIyImNTQ2MzIWEyE1EwEzNwPA/IADgPyAGiYmGgOAGiYmGoA4KCg4OCgoOED9AOABAEDgA0D9AAMAQCYa/QAaJiYaAwAaJuAoODgoKDg4/biAAYD+wMAAAAIAAABABAADQAA4ADwAAAEmJy4BJyYjIgcOAQcGBwYHDgEHBhUUFx4BFxYXFhceARcWMzI3PgE3Njc2Nz4BNzY1NCcuAScmJwERDQED1TY4OXY8PT8/PTx2OTg2CwcICwMDAwMLCAcLNjg5djw9Pz89PHY5ODYLBwgLAwMDAwsIBwv9qwFA/sADIAgGBggCAgICCAYGCCkqKlktLi8vLi1ZKiopCAYGCAICAgIIBgYIKSoqWS0uLy8uLVkqKin94AGAwMAAAAAAAgDA/8ADQAPAABsAJwAAASIHDgEHBhUUFx4BFxYxMDc+ATc2NTQnLgEnJgMiJjU0NjMyFhUUBgIAQjs6VxkZMjJ4MjIyMngyMhkZVzo7QlBwcFBQcHADwBkZVzo7Qnh9fcxBQUFBzH19eEI7OlcZGf4AcFBQcHBQUHAAAAEAAAAABAADgAArAAABIgcOAQcGBycRISc+ATMyFx4BFxYVFAcOAQcGBxc2Nz4BNzY1NCcuAScmIwIANTIyXCkpI5YBgJA1i1BQRUZpHh4JCSIYGB5VKCAgLQwMKCiLXl1qA4AKCycbHCOW/oCQNDweHmlGRVArKClJICEaYCMrK2I2NjlqXV6LKCgAAQAAAAAEAAOAACoAABMUFx4BFxYXNyYnLgEnJjU0Nz4BNzYzMhYXByERByYnLgEnJiMiBw4BBwYADAwtICAoVR4YGCIJCR4eaUZFUFCLNZABgJYjKSlcMjI1al1eiygoAYA5NjZiKysjYBohIEkpKCtQRUZpHh48NJABgJYjHBsnCwooKIteXQAAAAACAAAAQAQBAwAAJgBNAAATMhceARcWFRQHDgEHBiMiJy4BJyY1JzQ3PgE3NjMVIgYHDgEHPgEhMhceARcWFRQHDgEHBiMiJy4BJyY1JzQ3PgE3NjMVIgYHDgEHPgHhLikpPRESEhE9KSkuLikpPRESASMjelJRXUB1LQkQBwgSAkkuKSk9ERISET0pKS4uKSk9ERIBIyN6UlFdQHUtCRAHCBICABIRPSkpLi4pKT0REhIRPSkpLiBdUVJ6IyOAMC4IEwoCARIRPSkpLi4pKT0REhIRPSkpLiBdUVJ6IyOAMC4IEwoCAQAABgBA/8AEAAPAAAMABwALABEAHQApAAAlIRUhESEVIREhFSEnESM1IzUTFTMVIzU3NSM1MxUVESM1MzUjNTM1IzUBgAKA/YACgP2AAoD9gMBAQECAwICAwMCAgICAgIACAIACAIDA/wDAQP3yMkCSPDJAku7+wEBAQEBAAAYAAP/ABAADwAADAAcACwAXACMALwAAASEVIREhFSERIRUhATQ2MzIWFRQGIyImETQ2MzIWFRQGIyImETQ2MzIWFRQGIyImAYACgP2AAoD9gAKA/YD+gEs1NUtLNTVLSzU1S0s1NUtLNTVLSzU1SwOAgP8AgP8AgANANUtLNTVLS/61NUtLNTVLS/61NUtLNTVLSwADAAAAAAQAA6AAAwANABQAADchFSElFSE1EyEVITUhJQkBIxEjEQAEAPwABAD8AIABAAEAAQD9YAEgASDggEBAwEBAAQCAgMABIP7g/wABAAAAAAACAB7/zAPiA7QAMwBkAAABIiYnJicmNDc2PwE+ATMyFhcWFxYUBwYPAQYiJyY0PwE2NCcuASMiBg8BBhQXFhQHDgEjAyImJyYnJjQ3Nj8BNjIXFhQPAQYUFx4BMzI2PwE2NCcmNDc2MhcWFxYUBwYPAQ4BIwG4ChMIIxISEhIjwCNZMTFZIyMSEhISI1gPLA8PD1gpKRQzHBwzFMApKQ8PCBMKuDFZIyMSEhISI1gPLA8PD1gpKRQzHBwzFMApKQ8PDysQIxISEhIjwCNZMQFECAckLS1eLS0kwCIlJSIkLS1eLS0kVxAQDysPWCl0KRQVFRTAKXQpDysQBwj+iCUiJC0tXi0tJFcQEA8rD1gpdCkUFRUUwCl0KQ8rEA8PJC0tXi0tJMAiJQAAAAAFAAD/wAQAA8AAGwA3AFMAXwBrAAAFMjc+ATc2NTQnLgEnJiMiBw4BBwYVFBceARcWEzIXHgEXFhUUBw4BBwYjIicuAScmNTQ3PgE3NhMyNz4BNzY3BgcOAQcGIyInLgEnJicWFx4BFxYnNDYzMhYVFAYjIiYlNDYzMhYVFAYjIiYCAGpdXosoKCgoi15dampdXosoKCgoi15dalZMTHEgISEgcUxMVlZMTHEgISEgcUxMVisrKlEmJiMFHBtWODc/Pzc4VhscBSMmJlEqK9UlGxslJRsbJQGAJRsbJSUbGyVAKCiLXl1qal1eiygoKCiLXl1qal1eiygoA6AhIHFMTFZWTExxICEhIHFMTFZWTExxICH+CQYGFRAQFEM6OlYYGRkYVjo6QxQQEBUGBvcoODgoKDg4KCg4OCgoODgAAAMAAP/ABAADwAAbADcAQwAAASIHDgEHBhUUFx4BFxYzMjc+ATc2NTQnLgEnJgMiJy4BJyY1NDc+ATc2MzIXHgEXFhUUBw4BBwYTBycHFwcXNxc3JzcCAGpdXosoKCgoi15dampdXosoKCgoi15dalZMTHEgISEgcUxMVlZMTHEgISEgcUxMSqCgYKCgYKCgYKCgA8AoKIteXWpqXV6LKCgoKIteXWpqXV6LKCj8YCEgcUxMVlZMTHEgISEgcUxMVlZMTHEgIQKgoKBgoKBgoKBgoKAAAQBl/8ADmwPAACkAAAEiJiMiBw4BBwYVFBYzLgE1NDY3MAcGAgcGBxUhEzM3IzceATMyNjcOAQMgRGhGcVNUbRobSUgGDWVKEBBLPDxZAT1sxizXNC1VJi5QGB09A7AQHh1hPj9BTTsLJjeZbwN9fv7Fj5AjGQIAgPYJDzdrCQcAAAAAAgAAAAAEAAOAAAkAFwAAJTMHJzMRIzcXIyURJyMRMxUhNTMRIwcRA4CAoKCAgKCggP8AQMCA/oCAwEDAwMACAMDAwP8AgP1AQEACwIABAAADAMAAAANAA4AAFgAfACgAAAE+ATU0Jy4BJyYjIREhMjc+ATc2NTQmATMyFhUUBisBEyMRMzIWFRQGAsQcIBQURi4vNf7AAYA1Ly5GFBRE/oRlKjw8KWafn58sPj4B2yJULzUvLkYUFPyAFBRGLi81RnQBRks1NUv+gAEASzU1SwAAAAACAMAAAANAA4AAHwAjAAABMxEUBw4BBwYjIicuAScmNREzERQWFx4BMzI2Nz4BNQEhFSECwIAZGVc6O0JCOzpXGRmAGxgcSSgoSRwYG/4AAoD9gAOA/mA8NDVOFhcXFk41NDwBoP5gHjgXGBsbGBc4Hv6ggAAAAAABAIAAAAOAA4AACwAAARUjATMVITUzASM1A4CA/sCA/kCAAUCAA4BA/QBAQAMAQAABAAAAAAQAA4AAPQAAARUjHgEVFAYHDgEjIiYnLgE1MxQWMzI2NTQmIyE1IS4BJy4BNTQ2Nz4BMzIWFx4BFSM0JiMiBhUUFjMyFhcEAOsVFjUwLHE+PnEsMDWAck5OcnJO/gABLAIEATA1NTAscT4+cSwwNYByTk5yck47bisBwEAdQSI1YiQhJCQhJGI1NExMNDRMQAEDASRiNTViJCEkJCEkYjU0TEw0NEwhHwAAAAcAAP/ABAADwAADAAcACwAPABMAGwAjAAATMxUjNzMVIyUzFSM3MxUjJTMVIwMTIRMzEyETAQMhAyMDIQMAgIDAwMABAICAwMDAAQCAgBAQ/QAQIBACgBD9QBADABAgEP2AEAHAQEBAQEBAQEBAAkD+QAHA/oABgPwAAYD+gAFA/sAAAAoAAAAABAADgAADAAcACwAPABMAFwAbAB8AIwAnAAATESERATUhFR0BITUBFSE1IxUhNREhFSElIRUhETUhFQEhFSEhNSEVAAQA/YABAP8AAQD/AED/AAEA/wACgAEA/wABAPyAAQD/AAKAAQADgPyAA4D9wMDAQMDAAgDAwMDA/wDAwMABAMDA/sDAwMAAAAUAAAAABAADgAADAAcACwAPABMAABMhFSEVIRUhESEVIREhFSERIRUhAAQA/AACgP2AAoD9gAQA/AAEAPwAA4CAQID/AIABQID/AIAAAAAABQAAAAAEAAOAAAMABwALAA8AEwAAEyEVIRchFSERIRUhAyEVIREhFSEABAD8AMACgP2AAoD9gMAEAPwABAD8AAOAgECA/wCAAUCA/wCAAAAFAAAAAAQAA4AAAwAHAAsADwATAAATIRUhBSEVIREhFSEBIRUhESEVIQAEAPwAAYACgP2AAoD9gP6ABAD8AAQA/AADgIBAgP8AgAFAgP8AgAAAAAABAD8APwLmAuYALAAAJRQPAQYjIi8BBwYjIi8BJjU0PwEnJjU0PwE2MzIfATc2MzIfARYVFA8BFxYVAuYQThAXFxCoqBAXFhBOEBCoqBAQThAWFxCoqBAXFxBOEBCoqBDDFhBOEBCoqBAQThAWFxCoqBAXFxBOEBCoqBAQThAXFxCoqBAXAAAABgAAAAADJQNuABQAKAA8AE0AVQCCAAABERQHBisBIicmNRE0NzY7ATIXFhUzERQHBisBIicmNRE0NzY7ATIXFhcRFAcGKwEiJyY1ETQ3NjsBMhcWExEhERQXFhcWMyEyNzY3NjUBIScmJyMGBwUVFAcGKwERFAcGIyEiJyY1ESMiJyY9ATQ3NjsBNzY3NjsBMhcWHwEzMhcWFQElBgUIJAgFBgYFCCQIBQaSBQUIJQgFBQUFCCUIBQWSBQUIJQgFBQUFCCUIBQVJ/gAEBAUEAgHbAgQEBAT+gAEAGwQGtQYEAfcGBQg3Ghsm/iUmGxs3CAUFBQUIsSgIFxYXtxcWFgkosAgFBgIS/rcIBQUFBQgBSQgFBgYFCP63CAUFBQUIAUkIBQYGBQj+twgFBQUFCAFJCAUGBgX+WwId/eMNCwoFBQUFCgsNAmZDBQICBVUkCAYF/eMwIiMhIi8CIAUGCCQIBQVgFQ8PDw8VYAUFCAACAAcASQO3Aq8AGgAuAAAJAQYjIi8BJjU0PwEnJjU0PwE2MzIXARYVFAcBFRQHBiMhIicmPQE0NzYzITIXFgFO/vYGBwgFHQYG4eEGBh0FCAcGAQoGBgJpBQUI/dsIBQUFBQgCJQgFBQGF/vYGBhwGCAcG4OEGBwcGHQUF/vUFCAcG/vslCAUFBQUIJQgFBQUFAAAAAQAjAAAD3QNuALMAACUiJyYjIgcGIyInJjU0NzY3Njc2NzY9ATQnJiMhIgcGHQEUFxYXFjMWFxYVFAcGIyInJiMiBwYjIicmNTQ3Njc2NzY3Nj0BETQ1NDU0JzQnJicmJyYnJicmIyInJjU0NzYzMhcWMzI3NjMyFxYVFAcGIwYHBgcGHQEUFxYzITI3Nj0BNCcmJyYnJjU0NzYzMhcWMzI3NjMyFxYVFAcGByIHBgcGFREUFxYXFhcyFxYVFAcGIwPBGTMyGhkyMxkNCAcJCg0MERAKEgEHFf5+FgcBFQkSEw4ODAsHBw4bNTUaGDExGA0HBwkJCwwQDwkSAQIBAgMEBAUIEhENDQoLBwcOGjU1GhgwMRgOBwcJCgwNEBAIFAEHDwGQDgcBFAoXFw8OBwcOGTMyGRkxMRkOBwcKCg0NEBEIFBQJEREODQoLBwcOAAICAgIMCw8RCQkBAQMDBQxE4AwFAwMFDNRRDQYBAgEICBIPDA0CAgICDAwOEQgJAQIDAwUNRSEB0AINDQgIDg4KCgsLBwcDBgEBCAgSDwwNAgICAg0MDxEICAECAQYMULYMBwEBBwy2UAwGAQEGBxYPDA0CAgICDQwPEQgIAQECBg1P/eZEDAYCAgEJCBEPDA0AAAIAAP+3A/8DtwATADkAAAEyFxYVFAcCBwYjIicmNTQ3ATYzARYXFh8BFgcGIyInJicmJyY1FhcWFxYXFjMyNzY3Njc2NzY3NjcDmygeHhq+TDdFSDQ0NQFtISn9+BcmJy8BAkxMe0c2NiEhEBEEExQQEBIRCRcIDxITFRUdHR4eKQO3GxooJDP+mUY0NTRJSTABSx/9sSsfHw0oek1MGhsuLzo6RAMPDgsLCgoWJRsaEREKCwQEAgABAAAAAAAA9evv618PPPUACwQAAAAAANbEBFgAAAAA1sQEWAAA/7cEAQPAAAAACAACAAAAAAAAAAEAAAPA/8AAAAQAAAD//wQBAAEAAAAAAAAAAAAAAAAAAAAhBAAAAAAAAAAAAAAAAgAAAAQAAAAEAAAABAAAAAQAAMAEAAAABAAAAAQAAAAEAABABAAAAAQAAAAEAAAeBAAAAAQAAAAEAABlBAAAAAQAAMAEAADABAAAgAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAMlAD8DJQAAA74ABwQAACMD/wAAAAAAAAAKABQAHgBMAJQA+AE2AXwBwgI2AnQCvgLoA34EHgSIBMoE8gU0BXAFiAXgBiIGagaSBroG5AcoB+AIKgkcCXgAAQAAACEAtAAKAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAAcAAAABAAAAAAACAAcAYAABAAAAAAADAAcANgABAAAAAAAEAAcAdQABAAAAAAAFAAsAFQABAAAAAAAGAAcASwABAAAAAAAKABoAigADAAEECQABAA4ABwADAAEECQACAA4AZwADAAEECQADAA4APQADAAEECQAEAA4AfAADAAEECQAFABYAIAADAAEECQAGAA4AUgADAAEECQAKADQApGljb21vb24AaQBjAG8AbQBvAG8AblZlcnNpb24gMS4wAFYAZQByAHMAaQBvAG4AIAAxAC4AMGljb21vb24AaQBjAG8AbQBvAG8Abmljb21vb24AaQBjAG8AbQBvAG8AblJlZ3VsYXIAUgBlAGcAdQBsAGEAcmljb21vb24AaQBjAG8AbQBvAG8AbkZvbnQgZ2VuZXJhdGVkIGJ5IEljb01vb24uAEYAbwBuAHQAIABnAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4ALgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=) format('truetype'); + font-weight: normal; + font-style: normal; +} +[class^="w-e-icon-"], +[class*=" w-e-icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'w-e-icon' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.w-e-icon-close:before { + content: "\f00d"; +} +.w-e-icon-upload2:before { + content: "\e9c6"; +} +.w-e-icon-trash-o:before { + content: "\f014"; +} +.w-e-icon-header:before { + content: "\f1dc"; +} +.w-e-icon-pencil2:before { + content: "\e906"; +} +.w-e-icon-paint-brush:before { + content: "\f1fc"; +} +.w-e-icon-image:before { + content: "\e90d"; +} +.w-e-icon-play:before { + content: "\e912"; +} +.w-e-icon-location:before { + content: "\e947"; +} +.w-e-icon-undo:before { + content: "\e965"; +} +.w-e-icon-redo:before { + content: "\e966"; +} +.w-e-icon-quotes-left:before { + content: "\e977"; +} +.w-e-icon-list-numbered:before { + content: "\e9b9"; +} +.w-e-icon-list2:before { + content: "\e9bb"; +} +.w-e-icon-link:before { + content: "\e9cb"; +} +.w-e-icon-happy:before { + content: "\e9df"; +} +.w-e-icon-bold:before { + content: "\ea62"; +} +.w-e-icon-underline:before { + content: "\ea63"; +} +.w-e-icon-italic:before { + content: "\ea64"; +} +.w-e-icon-strikethrough:before { + content: "\ea65"; +} +.w-e-icon-table2:before { + content: "\ea71"; +} +.w-e-icon-paragraph-left:before { + content: "\ea77"; +} +.w-e-icon-paragraph-center:before { + content: "\ea78"; +} +.w-e-icon-paragraph-right:before { + content: "\ea79"; +} +.w-e-icon-terminal:before { + content: "\f120"; +} +.w-e-icon-page-break:before { + content: "\ea68"; +} +.w-e-icon-cancel-circle:before { + content: "\ea0d"; +} +.w-e-icon-font:before { + content: "\ea5c"; +} +.w-e-icon-text-heigh:before { + content: "\ea5f"; +} + +.w-e-toolbar { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + padding: 0 5px; + /* flex-wrap: wrap; */ + /* 单个菜单 */ +} +.w-e-toolbar .w-e-menu { + position: relative; + text-align: center; + padding: 5px 10px; + cursor: pointer; +} +.w-e-toolbar .w-e-menu i { + color: #999; +} +.w-e-toolbar .w-e-menu:hover i { + color: #333; +} +.w-e-toolbar .w-e-active i { + color: #1e88e5; +} +.w-e-toolbar .w-e-active:hover i { + color: #1e88e5; +} + +.w-e-text-container .w-e-panel-container { + position: absolute; + top: 0; + left: 50%; + border: 1px solid #ccc; + border-top: 0; + box-shadow: 1px 1px 2px #ccc; + color: #333; + background-color: #fff; + /* 为 emotion panel 定制的样式 */ + /* 上传图片的 panel 定制样式 */ +} +.w-e-text-container .w-e-panel-container .w-e-panel-close { + position: absolute; + right: 0; + top: 0; + padding: 5px; + margin: 2px 5px 0 0; + cursor: pointer; + color: #999; +} +.w-e-text-container .w-e-panel-container .w-e-panel-close:hover { + color: #333; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-title { + list-style: none; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + font-size: 14px; + margin: 2px 10px 0 10px; + border-bottom: 1px solid #f1f1f1; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-title .w-e-item { + padding: 3px 5px; + color: #999; + cursor: pointer; + margin: 0 3px; + position: relative; + top: 1px; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-title .w-e-active { + color: #333; + border-bottom: 1px solid #333; + cursor: default; + font-weight: 700; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content { + padding: 10px 15px 10px 15px; + font-size: 16px; + /* 输入框的样式 */ + /* 按钮的样式 */ +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input:focus, +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content textarea:focus, +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content button:focus { + outline: none; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content textarea { + width: 100%; + border: 1px solid #ccc; + padding: 5px; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content textarea:focus { + border-color: #1e88e5; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text] { + border: none; + border-bottom: 1px solid #ccc; + font-size: 14px; + height: 20px; + color: #333; + text-align: left; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text].small { + width: 30px; + text-align: center; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text].block { + display: block; + width: 100%; + margin: 10px 0; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text]:focus { + border-bottom: 2px solid #1e88e5; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button { + font-size: 14px; + color: #1e88e5; + border: none; + padding: 5px 10px; + background-color: #fff; + cursor: pointer; + border-radius: 3px; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.left { + float: left; + margin-right: 10px; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.right { + float: right; + margin-left: 10px; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.gray { + color: #999; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.red { + color: #c24f4a; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button:hover { + background-color: #f1f1f1; +} +.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container:after { + content: ""; + display: table; + clear: both; +} +.w-e-text-container .w-e-panel-container .w-e-emoticon-container .w-e-item { + cursor: pointer; + font-size: 18px; + padding: 0 3px; + display: inline-block; + *display: inline; + *zoom: 1; +} +.w-e-text-container .w-e-panel-container .w-e-up-img-container { + text-align: center; +} +.w-e-text-container .w-e-panel-container .w-e-up-img-container .w-e-up-btn { + display: inline-block; + *display: inline; + *zoom: 1; + color: #999; + cursor: pointer; + font-size: 60px; + line-height: 1; +} +.w-e-text-container .w-e-panel-container .w-e-up-img-container .w-e-up-btn:hover { + color: #333; +} + +.w-e-text-container { + position: relative; +} +.w-e-text-container .w-e-progress { + position: absolute; + background-color: #1e88e5; + bottom: 0; + left: 0; + height: 1px; +} +.w-e-text { + padding: 0 10px; + overflow-y: scroll; +} +.w-e-text p, +.w-e-text h1, +.w-e-text h2, +.w-e-text h3, +.w-e-text h4, +.w-e-text h5, +.w-e-text table, +.w-e-text pre { + margin: 10px 0; + line-height: 1.5; +} +.w-e-text ul, +.w-e-text ol { + margin: 10px 0 10px 20px; +} +.w-e-text blockquote { + display: block; + border-left: 8px solid #d0e5f2; + padding: 5px 10px; + margin: 10px 0; + line-height: 1.4; + font-size: 100%; + background-color: #f1f1f1; +} +.w-e-text code { + display: inline-block; + *display: inline; + *zoom: 1; + background-color: #f1f1f1; + border-radius: 3px; + padding: 3px 5px; + margin: 0 3px; +} +.w-e-text pre code { + display: block; +} +.w-e-text table { + border-top: 1px solid #ccc; + border-left: 1px solid #ccc; +} +.w-e-text table td, +.w-e-text table th { + border-bottom: 1px solid #ccc; + border-right: 1px solid #ccc; + padding: 3px 5px; +} +.w-e-text table th { + border-bottom: 2px solid #ccc; + text-align: center; +} +.w-e-text:focus { + outline: none; +} +.w-e-text img { + cursor: pointer; +} +.w-e-text img:hover { + box-shadow: 0 0 5px #333; +} diff --git a/ss-admin/src/main/resources/static/js/lay-module/wangEditor/wangEditor.js b/ss-admin/src/main/resources/static/js/lay-module/wangEditor/wangEditor.js new file mode 100644 index 0000000..fe909c8 --- /dev/null +++ b/ss-admin/src/main/resources/static/js/lay-module/wangEditor/wangEditor.js @@ -0,0 +1,4678 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.wangEditor = factory()); +}(this, (function () { 'use strict'; + +/* + poly-fill +*/ + +var polyfill = function () { + + // Object.assign + if (typeof Object.assign != 'function') { + Object.assign = function (target, varArgs) { + // .length of function is 2 + if (target == null) { + // TypeError if undefined or null + throw new TypeError('Cannot convert undefined or null to object'); + } + + var to = Object(target); + + for (var index = 1; index < arguments.length; index++) { + var nextSource = arguments[index]; + + if (nextSource != null) { + // Skip over if undefined or null + for (var nextKey in nextSource) { + // Avoid bugs when hasOwnProperty is shadowed + if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { + to[nextKey] = nextSource[nextKey]; + } + } + } + } + return to; + }; + } + + // IE 中兼容 Element.prototype.matches + if (!Element.prototype.matches) { + Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || Element.prototype.webkitMatchesSelector || function (s) { + var matches = (this.document || this.ownerDocument).querySelectorAll(s), + i = matches.length; + while (--i >= 0 && matches.item(i) !== this) {} + return i > -1; + }; + } +}; + +/* + DOM 操作 API +*/ + +// 根据 html 代码片段创建 dom 对象 +function createElemByHTML(html) { + var div = void 0; + div = document.createElement('div'); + div.innerHTML = html; + return div.children; +} + +// 是否是 DOM List +function isDOMList(selector) { + if (!selector) { + return false; + } + if (selector instanceof HTMLCollection || selector instanceof NodeList) { + return true; + } + return false; +} + +// 封装 document.querySelectorAll +function querySelectorAll(selector) { + var result = document.querySelectorAll(selector); + if (isDOMList(result)) { + return result; + } else { + return [result]; + } +} + +// 记录所有的事件绑定 +var eventList = []; + +// 创建构造函数 +function DomElement(selector) { + if (!selector) { + return; + } + + // selector 本来就是 DomElement 对象,直接返回 + if (selector instanceof DomElement) { + return selector; + } + + this.selector = selector; + var nodeType = selector.nodeType; + + // 根据 selector 得出的结果(如 DOM,DOM List) + var selectorResult = []; + if (nodeType === 9) { + // document 节点 + selectorResult = [selector]; + } else if (nodeType === 1) { + // 单个 DOM 节点 + selectorResult = [selector]; + } else if (isDOMList(selector) || selector instanceof Array) { + // DOM List 或者数组 + selectorResult = selector; + } else if (typeof selector === 'string') { + // 字符串 + selector = selector.replace('/\n/mg', '').trim(); + if (selector.indexOf('<') === 0) { + // 如
    + selectorResult = createElemByHTML(selector); + } else { + // 如 #id .class + selectorResult = querySelectorAll(selector); + } + } + + var length = selectorResult.length; + if (!length) { + // 空数组 + return this; + } + + // 加入 DOM 节点 + var i = void 0; + for (i = 0; i < length; i++) { + this[i] = selectorResult[i]; + } + this.length = length; +} + +// 修改原型 +DomElement.prototype = { + constructor: DomElement, + + // 类数组,forEach + forEach: function forEach(fn) { + var i = void 0; + for (i = 0; i < this.length; i++) { + var elem = this[i]; + var result = fn.call(elem, elem, i); + if (result === false) { + break; + } + } + return this; + }, + + // clone + clone: function clone(deep) { + var cloneList = []; + this.forEach(function (elem) { + cloneList.push(elem.cloneNode(!!deep)); + }); + return $(cloneList); + }, + + // 获取第几个元素 + get: function get(index) { + var length = this.length; + if (index >= length) { + index = index % length; + } + return $(this[index]); + }, + + // 第一个 + first: function first() { + return this.get(0); + }, + + // 最后一个 + last: function last() { + var length = this.length; + return this.get(length - 1); + }, + + // 绑定事件 + on: function on(type, selector, fn) { + // selector 不为空,证明绑定事件要加代理 + if (!fn) { + fn = selector; + selector = null; + } + + // type 是否有多个 + var types = []; + types = type.split(/\s+/); + + return this.forEach(function (elem) { + types.forEach(function (type) { + if (!type) { + return; + } + + // 记录下,方便后面解绑 + eventList.push({ + elem: elem, + type: type, + fn: fn + }); + + if (!selector) { + // 无代理 + elem.addEventListener(type, fn); + return; + } + + // 有代理 + elem.addEventListener(type, function (e) { + var target = e.target; + if (target.matches(selector)) { + fn.call(target, e); + } + }); + }); + }); + }, + + // 取消事件绑定 + off: function off(type, fn) { + return this.forEach(function (elem) { + elem.removeEventListener(type, fn); + }); + }, + + // 获取/设置 属性 + attr: function attr(key, val) { + if (val == null) { + // 获取值 + return this[0].getAttribute(key); + } else { + // 设置值 + return this.forEach(function (elem) { + elem.setAttribute(key, val); + }); + } + }, + + // 添加 class + addClass: function addClass(className) { + if (!className) { + return this; + } + return this.forEach(function (elem) { + var arr = void 0; + if (elem.className) { + // 解析当前 className 转换为数组 + arr = elem.className.split(/\s/); + arr = arr.filter(function (item) { + return !!item.trim(); + }); + // 添加 class + if (arr.indexOf(className) < 0) { + arr.push(className); + } + // 修改 elem.class + elem.className = arr.join(' '); + } else { + elem.className = className; + } + }); + }, + + // 删除 class + removeClass: function removeClass(className) { + if (!className) { + return this; + } + return this.forEach(function (elem) { + var arr = void 0; + if (elem.className) { + // 解析当前 className 转换为数组 + arr = elem.className.split(/\s/); + arr = arr.filter(function (item) { + item = item.trim(); + // 删除 class + if (!item || item === className) { + return false; + } + return true; + }); + // 修改 elem.class + elem.className = arr.join(' '); + } + }); + }, + + // 修改 css + css: function css(key, val) { + var currentStyle = key + ':' + val + ';'; + return this.forEach(function (elem) { + var style = (elem.getAttribute('style') || '').trim(); + var styleArr = void 0, + resultArr = []; + if (style) { + // 将 style 按照 ; 拆分为数组 + styleArr = style.split(';'); + styleArr.forEach(function (item) { + // 对每项样式,按照 : 拆分为 key 和 value + var arr = item.split(':').map(function (i) { + return i.trim(); + }); + if (arr.length === 2) { + resultArr.push(arr[0] + ':' + arr[1]); + } + }); + // 替换或者新增 + resultArr = resultArr.map(function (item) { + if (item.indexOf(key) === 0) { + return currentStyle; + } else { + return item; + } + }); + if (resultArr.indexOf(currentStyle) < 0) { + resultArr.push(currentStyle); + } + // 结果 + elem.setAttribute('style', resultArr.join('; ')); + } else { + // style 无值 + elem.setAttribute('style', currentStyle); + } + }); + }, + + // 显示 + show: function show() { + return this.css('display', 'block'); + }, + + // 隐藏 + hide: function hide() { + return this.css('display', 'none'); + }, + + // 获取子节点 + children: function children() { + var elem = this[0]; + if (!elem) { + return null; + } + + return $(elem.children); + }, + + // 获取子节点(包括文本节点) + childNodes: function childNodes() { + var elem = this[0]; + if (!elem) { + return null; + } + + return $(elem.childNodes); + }, + + // 增加子节点 + append: function append($children) { + return this.forEach(function (elem) { + $children.forEach(function (child) { + elem.appendChild(child); + }); + }); + }, + + // 移除当前节点 + remove: function remove() { + return this.forEach(function (elem) { + if (elem.remove) { + elem.remove(); + } else { + var parent = elem.parentElement; + parent && parent.removeChild(elem); + } + }); + }, + + // 是否包含某个子节点 + isContain: function isContain($child) { + var elem = this[0]; + var child = $child[0]; + return elem.contains(child); + }, + + // 尺寸数据 + getSizeData: function getSizeData() { + var elem = this[0]; + return elem.getBoundingClientRect(); // 可得到 bottom height left right top width 的数据 + }, + + // 封装 nodeName + getNodeName: function getNodeName() { + var elem = this[0]; + return elem.nodeName; + }, + + // 从当前元素查找 + find: function find(selector) { + var elem = this[0]; + return $(elem.querySelectorAll(selector)); + }, + + // 获取当前元素的 text + text: function text(val) { + if (!val) { + // 获取 text + var elem = this[0]; + return elem.innerHTML.replace(/<.*?>/g, function () { + return ''; + }); + } else { + // 设置 text + return this.forEach(function (elem) { + elem.innerHTML = val; + }); + } + }, + + // 获取 html + html: function html(value) { + var elem = this[0]; + if (value == null) { + return elem.innerHTML; + } else { + elem.innerHTML = value; + return this; + } + }, + + // 获取 value + val: function val() { + var elem = this[0]; + return elem.value.trim(); + }, + + // focus + focus: function focus() { + return this.forEach(function (elem) { + elem.focus(); + }); + }, + + // parent + parent: function parent() { + var elem = this[0]; + return $(elem.parentElement); + }, + + // parentUntil 找到符合 selector 的父节点 + parentUntil: function parentUntil(selector, _currentElem) { + var results = document.querySelectorAll(selector); + var length = results.length; + if (!length) { + // 传入的 selector 无效 + return null; + } + + var elem = _currentElem || this[0]; + if (elem.nodeName === 'BODY') { + return null; + } + + var parent = elem.parentElement; + var i = void 0; + for (i = 0; i < length; i++) { + if (parent === results[i]) { + // 找到,并返回 + return $(parent); + } + } + + // 继续查找 + return this.parentUntil(selector, parent); + }, + + // 判断两个 elem 是否相等 + equal: function equal($elem) { + if ($elem.nodeType === 1) { + return this[0] === $elem; + } else { + return this[0] === $elem[0]; + } + }, + + // 将该元素插入到某个元素前面 + insertBefore: function insertBefore(selector) { + var $referenceNode = $(selector); + var referenceNode = $referenceNode[0]; + if (!referenceNode) { + return this; + } + return this.forEach(function (elem) { + var parent = referenceNode.parentNode; + parent.insertBefore(elem, referenceNode); + }); + }, + + // 将该元素插入到某个元素后面 + insertAfter: function insertAfter(selector) { + var $referenceNode = $(selector); + var referenceNode = $referenceNode[0]; + if (!referenceNode) { + return this; + } + return this.forEach(function (elem) { + var parent = referenceNode.parentNode; + if (parent.lastChild === referenceNode) { + // 最后一个元素 + parent.appendChild(elem); + } else { + // 不是最后一个元素 + parent.insertBefore(elem, referenceNode.nextSibling); + } + }); + } +}; + +// new 一个对象 +function $(selector) { + return new DomElement(selector); +} + +// 解绑所有事件,用于销毁编辑器 +$.offAll = function () { + eventList.forEach(function (item) { + var elem = item.elem; + var type = item.type; + var fn = item.fn; + // 解绑 + elem.removeEventListener(type, fn); + }); +}; + +/* + 配置信息 +*/ + +var config = { + + // 默认菜单配置 + menus: ['head', 'bold', 'fontSize', 'fontName', 'italic', 'underline', 'strikeThrough', 'foreColor', 'backColor', 'link', 'list', 'justify', 'quote', 'emoticon', 'image', 'table', 'video', 'code', 'undo', 'redo'], + + fontNames: ['宋体', '微软雅黑', 'Arial', 'Tahoma', 'Verdana'], + + colors: ['#000000', '#eeece0', '#1c487f', '#4d80bf', '#c24f4a', '#8baa4a', '#7b5ba1', '#46acc8', '#f9963b', '#ffffff'], + + // // 语言配置 + // lang: { + // '设置标题': 'title', + // '正文': 'p', + // '链接文字': 'link text', + // '链接': 'link', + // '插入': 'insert', + // '创建': 'init' + // }, + + // 表情 + emotions: [{ + // tab 的标题 + title: '默认', + // type -> 'emoji' / 'image' + type: 'image', + // content -> 数组 + content: [{ + alt: '[坏笑]', + src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/50/pcmoren_huaixiao_org.png' + }, { + alt: '[舔屏]', + src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/40/pcmoren_tian_org.png' + }, { + alt: '[污]', + src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/3c/pcmoren_wu_org.png' + }] + }, { + // tab 的标题 + title: '新浪', + // type -> 'emoji' / 'image' + type: 'image', + // content -> 数组 + content: [{ + src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/7a/shenshou_thumb.gif', + alt: '[草泥马]' + }, { + src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/60/horse2_thumb.gif', + alt: '[神马]' + }, { + src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/bc/fuyun_thumb.gif', + alt: '[浮云]' + }] + }, { + // tab 的标题 + title: 'emoji', + // type -> 'emoji' / 'image' + type: 'emoji', + // content -> 数组 + content: '😀 😃 😄 😁 😆 😅 😂 😊 😇 🙂 🙃 😉 😓 😪 😴 🙄 🤔 😬 🤐'.split(/\s/) + }], + + // 编辑区域的 z-index + zIndex: 10000, + + // 是否开启 debug 模式(debug 模式下错误会 throw error 形式抛出) + debug: false, + + // 插入链接时候的格式校验 + linkCheck: function linkCheck(text, link) { + // text 是插入的文字 + // link 是插入的链接 + return true; // 返回 true 即表示成功 + // return '校验失败' // 返回字符串即表示失败的提示信息 + }, + + // 插入网络图片的校验 + linkImgCheck: function linkImgCheck(src) { + // src 即图片的地址 + return true; // 返回 true 即表示成功 + // return '校验失败' // 返回字符串即表示失败的提示信息 + }, + + // 粘贴过滤样式,默认开启 + pasteFilterStyle: true, + + // 粘贴内容时,忽略图片。默认关闭 + pasteIgnoreImg: false, + + // 对粘贴的文字进行自定义处理,返回处理后的结果。编辑器会将处理后的结果粘贴到编辑区域中。 + // IE 暂时不支持 + pasteTextHandle: function pasteTextHandle(content) { + // content 即粘贴过来的内容(html 或 纯文本),可进行自定义处理然后返回 + return content; + }, + + // onchange 事件 + // onchange: function (html) { + // // html 即变化之后的内容 + // console.log(html) + // }, + + // 是否显示添加网络图片的 tab + showLinkImg: true, + + // 插入网络图片的回调 + linkImgCallback: function linkImgCallback(url) { + // console.log(url) // url 即插入图片的地址 + }, + + // 默认上传图片 max size: 5M + uploadImgMaxSize: 5 * 1024 * 1024, + + // 配置一次最多上传几个图片 + // uploadImgMaxLength: 5, + + // 上传图片,是否显示 base64 格式 + uploadImgShowBase64: false, + + // 上传图片,server 地址(如果有值,则 base64 格式的配置则失效) + // uploadImgServer: '/upload', + + // 自定义配置 filename + uploadFileName: '', + + // 上传图片的自定义参数 + uploadImgParams: { + // token: 'abcdef12345' + }, + + // 上传图片的自定义header + uploadImgHeaders: { + // 'Accept': 'text/x-json' + }, + + // 配置 XHR withCredentials + withCredentials: false, + + // 自定义上传图片超时时间 ms + uploadImgTimeout: 10000, + + // 上传图片 hook + uploadImgHooks: { + // customInsert: function (insertLinkImg, result, editor) { + // console.log('customInsert') + // // 图片上传并返回结果,自定义插入图片的事件,而不是编辑器自动插入图片 + // const data = result.data1 || [] + // data.forEach(link => { + // insertLinkImg(link) + // }) + // }, + before: function before(xhr, editor, files) { + // 图片上传之前触发 + + // 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传 + // return { + // prevent: true, + // msg: '放弃上传' + // } + }, + success: function success(xhr, editor, result) { + // 图片上传并返回结果,图片插入成功之后触发 + }, + fail: function fail(xhr, editor, result) { + // 图片上传并返回结果,但图片插入错误时触发 + }, + error: function error(xhr, editor) { + // 图片上传出错时触发 + }, + timeout: function timeout(xhr, editor) { + // 图片上传超时时触发 + } + }, + + // 是否上传七牛云,默认为 false + qiniu: false + +}; + +/* + 工具 +*/ + +// 和 UA 相关的属性 +var UA = { + _ua: navigator.userAgent, + + // 是否 webkit + isWebkit: function isWebkit() { + var reg = /webkit/i; + return reg.test(this._ua); + }, + + // 是否 IE + isIE: function isIE() { + return 'ActiveXObject' in window; + } +}; + +// 遍历对象 +function objForEach(obj, fn) { + var key = void 0, + result = void 0; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + result = fn.call(obj, key, obj[key]); + if (result === false) { + break; + } + } + } +} + +// 遍历类数组 +function arrForEach(fakeArr, fn) { + var i = void 0, + item = void 0, + result = void 0; + var length = fakeArr.length || 0; + for (i = 0; i < length; i++) { + item = fakeArr[i]; + result = fn.call(fakeArr, item, i); + if (result === false) { + break; + } + } +} + +// 获取随机数 +function getRandom(prefix) { + return prefix + Math.random().toString().slice(2); +} + +// 替换 html 特殊字符 +function replaceHtmlSymbol(html) { + if (html == null) { + return ''; + } + return html.replace(//gm, '>').replace(/"/gm, '"').replace(/(\r\n|\r|\n)/g, '
    '); +} + +// 返回百分比的格式 + + +// 判断是不是 function +function isFunction(fn) { + return typeof fn === 'function'; +} + +/* + bold-menu +*/ +// 构造函数 +function Bold(editor) { + this.editor = editor; + this.$elem = $('
    \n \n
    '); + this.type = 'click'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Bold.prototype = { + constructor: Bold, + + // 点击事件 + onClick: function onClick(e) { + // 点击菜单将触发这里 + + var editor = this.editor; + var isSeleEmpty = editor.selection.isSelectionEmpty(); + + if (isSeleEmpty) { + // 选区是空的,插入并选中一个“空白” + editor.selection.createEmptyRange(); + } + + // 执行 bold 命令 + editor.cmd.do('bold'); + + if (isSeleEmpty) { + // 需要将选取折叠起来 + editor.selection.collapseRange(); + editor.selection.restoreSelection(); + } + }, + + // 试图改变 active 状态 + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + if (editor.cmd.queryCommandState('bold')) { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + 替换多语言 + */ + +var replaceLang = function (editor, str) { + var langArgs = editor.config.langArgs || []; + var result = str; + + langArgs.forEach(function (item) { + var reg = item.reg; + var val = item.val; + + if (reg.test(result)) { + result = result.replace(reg, function () { + return val; + }); + } + }); + + return result; +}; + +/* + droplist +*/ +var _emptyFn = function _emptyFn() {}; + +// 构造函数 +function DropList(menu, opt) { + var _this = this; + + // droplist 所依附的菜单 + var editor = menu.editor; + this.menu = menu; + this.opt = opt; + // 容器 + var $container = $('
    '); + + // 标题 + var $title = opt.$title; + var titleHtml = void 0; + if ($title) { + // 替换多语言 + titleHtml = $title.html(); + titleHtml = replaceLang(editor, titleHtml); + $title.html(titleHtml); + + $title.addClass('w-e-dp-title'); + $container.append($title); + } + + var list = opt.list || []; + var type = opt.type || 'list'; // 'list' 列表形式(如“标题”菜单) / 'inline-block' 块状形式(如“颜色”菜单) + var onClick = opt.onClick || _emptyFn; + + // 加入 DOM 并绑定事件 + var $list = $('
      '); + $container.append($list); + list.forEach(function (item) { + var $elem = item.$elem; + + // 替换多语言 + var elemHtml = $elem.html(); + elemHtml = replaceLang(editor, elemHtml); + $elem.html(elemHtml); + + var value = item.value; + var $li = $('
    • '); + if ($elem) { + $li.append($elem); + $list.append($li); + $li.on('click', function (e) { + onClick(value); + + // 隐藏 + _this.hideTimeoutId = setTimeout(function () { + _this.hide(); + }, 0); + }); + } + }); + + // 绑定隐藏事件 + $container.on('mouseleave', function (e) { + _this.hideTimeoutId = setTimeout(function () { + _this.hide(); + }, 0); + }); + + // 记录属性 + this.$container = $container; + + // 基本属性 + this._rendered = false; + this._show = false; +} + +// 原型 +DropList.prototype = { + constructor: DropList, + + // 显示(插入DOM) + show: function show() { + if (this.hideTimeoutId) { + // 清除之前的定时隐藏 + clearTimeout(this.hideTimeoutId); + } + + var menu = this.menu; + var $menuELem = menu.$elem; + var $container = this.$container; + if (this._show) { + return; + } + if (this._rendered) { + // 显示 + $container.show(); + } else { + // 加入 DOM 之前先定位位置 + var menuHeight = $menuELem.getSizeData().height || 0; + var width = this.opt.width || 100; // 默认为 100 + $container.css('margin-top', menuHeight + 'px').css('width', width + 'px'); + + // 加入到 DOM + $menuELem.append($container); + this._rendered = true; + } + + // 修改属性 + this._show = true; + }, + + // 隐藏(移除DOM) + hide: function hide() { + if (this.showTimeoutId) { + // 清除之前的定时显示 + clearTimeout(this.showTimeoutId); + } + + var $container = this.$container; + if (!this._show) { + return; + } + // 隐藏并需改属性 + $container.hide(); + this._show = false; + } +}; + +/* + menu - header +*/ +// 构造函数 +function Head(editor) { + var _this = this; + + this.editor = editor; + this.$elem = $('
      '); + this.type = 'droplist'; + + // 当前是否 active 状态 + this._active = false; + + // 初始化 droplist + this.droplist = new DropList(this, { + width: 100, + $title: $('

      设置标题

      '), + type: 'list', // droplist 以列表形式展示 + list: [{ $elem: $('

      H1

      '), value: '

      ' }, { $elem: $('

      H2

      '), value: '

      ' }, { $elem: $('

      H3

      '), value: '

      ' }, { $elem: $('

      H4

      '), value: '

      ' }, { $elem: $('

      H5
      '), value: '
      ' }, { $elem: $('

      正文

      '), value: '

      ' }], + onClick: function onClick(value) { + // 注意 this 是指向当前的 Head 对象 + _this._command(value); + } + }); +} + +// 原型 +Head.prototype = { + constructor: Head, + + // 执行命令 + _command: function _command(value) { + var editor = this.editor; + + var $selectionElem = editor.selection.getSelectionContainerElem(); + if (editor.$textElem.equal($selectionElem)) { + // 不能选中多行来设置标题,否则会出现问题 + // 例如选中的是

      xxx

      yyy

      来设置标题,设置之后会成为

      xxx
      yyy

      不符合预期 + return; + } + + editor.cmd.do('formatBlock', value); + }, + + // 试图改变 active 状态 + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + var reg = /^h/i; + var cmdValue = editor.cmd.queryCommandValue('formatBlock'); + if (reg.test(cmdValue)) { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + menu - fontSize +*/ + +// 构造函数 +function FontSize(editor) { + var _this = this; + + this.editor = editor; + this.$elem = $('
      '); + this.type = 'droplist'; + + // 当前是否 active 状态 + this._active = false; + + // 初始化 droplist + this.droplist = new DropList(this, { + width: 160, + $title: $('

      字号

      '), + type: 'list', // droplist 以列表形式展示 + list: [{ $elem: $('x-small'), value: '1' }, { $elem: $('small'), value: '2' }, { $elem: $('normal'), value: '3' }, { $elem: $('large'), value: '4' }, { $elem: $('x-large'), value: '5' }, { $elem: $('xx-large'), value: '6' }], + onClick: function onClick(value) { + // 注意 this 是指向当前的 FontSize 对象 + _this._command(value); + } + }); +} + +// 原型 +FontSize.prototype = { + constructor: FontSize, + + // 执行命令 + _command: function _command(value) { + var editor = this.editor; + editor.cmd.do('fontSize', value); + } +}; + +/* + menu - fontName +*/ + +// 构造函数 +function FontName(editor) { + var _this = this; + + this.editor = editor; + this.$elem = $('
      '); + this.type = 'droplist'; + + // 当前是否 active 状态 + this._active = false; + + // 获取配置的字体 + var config = editor.config; + var fontNames = config.fontNames || []; + + // 初始化 droplist + this.droplist = new DropList(this, { + width: 100, + $title: $('

      字体

      '), + type: 'list', // droplist 以列表形式展示 + list: fontNames.map(function (fontName) { + return { $elem: $('' + fontName + ''), value: fontName }; + }), + onClick: function onClick(value) { + // 注意 this 是指向当前的 FontName 对象 + _this._command(value); + } + }); +} + +// 原型 +FontName.prototype = { + constructor: FontName, + + _command: function _command(value) { + var editor = this.editor; + editor.cmd.do('fontName', value); + } +}; + +/* + panel +*/ + +var emptyFn = function emptyFn() {}; + +// 记录已经显示 panel 的菜单 +var _isCreatedPanelMenus = []; + +// 构造函数 +function Panel(menu, opt) { + this.menu = menu; + this.opt = opt; +} + +// 原型 +Panel.prototype = { + constructor: Panel, + + // 显示(插入DOM) + show: function show() { + var _this = this; + + var menu = this.menu; + if (_isCreatedPanelMenus.indexOf(menu) >= 0) { + // 该菜单已经创建了 panel 不能再创建 + return; + } + + var editor = menu.editor; + var $body = $('body'); + var $textContainerElem = editor.$textContainerElem; + var opt = this.opt; + + // panel 的容器 + var $container = $('
      '); + var width = opt.width || 300; // 默认 300px + $container.css('width', width + 'px').css('margin-left', (0 - width) / 2 + 'px'); + + // 添加关闭按钮 + var $closeBtn = $(''); + $container.append($closeBtn); + $closeBtn.on('click', function () { + _this.hide(); + }); + + // 准备 tabs 容器 + var $tabTitleContainer = $('
        '); + var $tabContentContainer = $('
        '); + $container.append($tabTitleContainer).append($tabContentContainer); + + // 设置高度 + var height = opt.height; + if (height) { + $tabContentContainer.css('height', height + 'px').css('overflow-y', 'auto'); + } + + // tabs + var tabs = opt.tabs || []; + var tabTitleArr = []; + var tabContentArr = []; + tabs.forEach(function (tab, tabIndex) { + if (!tab) { + return; + } + var title = tab.title || ''; + var tpl = tab.tpl || ''; + + // 替换多语言 + title = replaceLang(editor, title); + tpl = replaceLang(editor, tpl); + + // 添加到 DOM + var $title = $('
      • ' + title + '
      • '); + $tabTitleContainer.append($title); + var $content = $(tpl); + $tabContentContainer.append($content); + + // 记录到内存 + $title._index = tabIndex; + tabTitleArr.push($title); + tabContentArr.push($content); + + // 设置 active 项 + if (tabIndex === 0) { + $title._active = true; + $title.addClass('w-e-active'); + } else { + $content.hide(); + } + + // 绑定 tab 的事件 + $title.on('click', function (e) { + if ($title._active) { + return; + } + // 隐藏所有的 tab + tabTitleArr.forEach(function ($title) { + $title._active = false; + $title.removeClass('w-e-active'); + }); + tabContentArr.forEach(function ($content) { + $content.hide(); + }); + + // 显示当前的 tab + $title._active = true; + $title.addClass('w-e-active'); + $content.show(); + }); + }); + + // 绑定关闭事件 + $container.on('click', function (e) { + // 点击时阻止冒泡 + e.stopPropagation(); + }); + $body.on('click', function (e) { + _this.hide(); + }); + + // 添加到 DOM + $textContainerElem.append($container); + + // 绑定 opt 的事件,只有添加到 DOM 之后才能绑定成功 + tabs.forEach(function (tab, index) { + if (!tab) { + return; + } + var events = tab.events || []; + events.forEach(function (event) { + var selector = event.selector; + var type = event.type; + var fn = event.fn || emptyFn; + var $content = tabContentArr[index]; + $content.find(selector).on(type, function (e) { + e.stopPropagation(); + var needToHide = fn(e); + // 执行完事件之后,是否要关闭 panel + if (needToHide) { + _this.hide(); + } + }); + }); + }); + + // focus 第一个 elem + var $inputs = $container.find('input[type=text],textarea'); + if ($inputs.length) { + $inputs.get(0).focus(); + } + + // 添加到属性 + this.$container = $container; + + // 隐藏其他 panel + this._hideOtherPanels(); + // 记录该 menu 已经创建了 panel + _isCreatedPanelMenus.push(menu); + }, + + // 隐藏(移除DOM) + hide: function hide() { + var menu = this.menu; + var $container = this.$container; + if ($container) { + $container.remove(); + } + + // 将该 menu 记录中移除 + _isCreatedPanelMenus = _isCreatedPanelMenus.filter(function (item) { + if (item === menu) { + return false; + } else { + return true; + } + }); + }, + + // 一个 panel 展示时,隐藏其他 panel + _hideOtherPanels: function _hideOtherPanels() { + if (!_isCreatedPanelMenus.length) { + return; + } + _isCreatedPanelMenus.forEach(function (menu) { + var panel = menu.panel || {}; + if (panel.hide) { + panel.hide(); + } + }); + } +}; + +/* + menu - link +*/ +// 构造函数 +function Link(editor) { + this.editor = editor; + this.$elem = $('
        '); + this.type = 'panel'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Link.prototype = { + constructor: Link, + + // 点击事件 + onClick: function onClick(e) { + var editor = this.editor; + var $linkelem = void 0; + + if (this._active) { + // 当前选区在链接里面 + $linkelem = editor.selection.getSelectionContainerElem(); + if (!$linkelem) { + return; + } + // 将该元素都包含在选取之内,以便后面整体替换 + editor.selection.createRangeByElem($linkelem); + editor.selection.restoreSelection(); + // 显示 panel + this._createPanel($linkelem.text(), $linkelem.attr('href')); + } else { + // 当前选区不在链接里面 + if (editor.selection.isSelectionEmpty()) { + // 选区是空的,未选中内容 + this._createPanel('', ''); + } else { + // 选中内容了 + this._createPanel(editor.selection.getSelectionText(), ''); + } + } + }, + + // 创建 panel + _createPanel: function _createPanel(text, link) { + var _this = this; + + // panel 中需要用到的id + var inputLinkId = getRandom('input-link'); + var inputTextId = getRandom('input-text'); + var btnOkId = getRandom('btn-ok'); + var btnDelId = getRandom('btn-del'); + + // 是否显示“删除链接” + var delBtnDisplay = this._active ? 'inline-block' : 'none'; + + // 初始化并显示 panel + var panel = new Panel(this, { + width: 300, + // panel 中可包含多个 tab + tabs: [{ + // tab 的标题 + title: '链接', + // 模板 + tpl: '
        \n \n \n
        \n \n \n
        \n
        ', + // 事件绑定 + events: [ + // 插入链接 + { + selector: '#' + btnOkId, + type: 'click', + fn: function fn() { + // 执行插入链接 + var $link = $('#' + inputLinkId); + var $text = $('#' + inputTextId); + var link = $link.val(); + var text = $text.val(); + _this._insertLink(text, link); + + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }, + // 删除链接 + { + selector: '#' + btnDelId, + type: 'click', + fn: function fn() { + // 执行删除链接 + _this._delLink(); + + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }] + } // tab end + ] // tabs end + }); + + // 显示 panel + panel.show(); + + // 记录属性 + this.panel = panel; + }, + + // 删除当前链接 + _delLink: function _delLink() { + if (!this._active) { + return; + } + var editor = this.editor; + var $selectionELem = editor.selection.getSelectionContainerElem(); + if (!$selectionELem) { + return; + } + var selectionText = editor.selection.getSelectionText(); + editor.cmd.do('insertHTML', '' + selectionText + ''); + }, + + // 插入链接 + _insertLink: function _insertLink(text, link) { + var editor = this.editor; + var config = editor.config; + var linkCheck = config.linkCheck; + var checkResult = true; // 默认为 true + if (linkCheck && typeof linkCheck === 'function') { + checkResult = linkCheck(text, link); + } + if (checkResult === true) { + editor.cmd.do('insertHTML', '' + text + ''); + } else { + alert(checkResult); + } + }, + + // 试图改变 active 状态 + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + var $selectionELem = editor.selection.getSelectionContainerElem(); + if (!$selectionELem) { + return; + } + if ($selectionELem.getNodeName() === 'A') { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + italic-menu +*/ +// 构造函数 +function Italic(editor) { + this.editor = editor; + this.$elem = $('
        \n \n
        '); + this.type = 'click'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Italic.prototype = { + constructor: Italic, + + // 点击事件 + onClick: function onClick(e) { + // 点击菜单将触发这里 + + var editor = this.editor; + var isSeleEmpty = editor.selection.isSelectionEmpty(); + + if (isSeleEmpty) { + // 选区是空的,插入并选中一个“空白” + editor.selection.createEmptyRange(); + } + + // 执行 italic 命令 + editor.cmd.do('italic'); + + if (isSeleEmpty) { + // 需要将选取折叠起来 + editor.selection.collapseRange(); + editor.selection.restoreSelection(); + } + }, + + // 试图改变 active 状态 + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + if (editor.cmd.queryCommandState('italic')) { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + redo-menu +*/ +// 构造函数 +function Redo(editor) { + this.editor = editor; + this.$elem = $('
        \n \n
        '); + this.type = 'click'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Redo.prototype = { + constructor: Redo, + + // 点击事件 + onClick: function onClick(e) { + // 点击菜单将触发这里 + + var editor = this.editor; + + // 执行 redo 命令 + editor.cmd.do('redo'); + } +}; + +/* + strikeThrough-menu +*/ +// 构造函数 +function StrikeThrough(editor) { + this.editor = editor; + this.$elem = $('
        \n \n
        '); + this.type = 'click'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +StrikeThrough.prototype = { + constructor: StrikeThrough, + + // 点击事件 + onClick: function onClick(e) { + // 点击菜单将触发这里 + + var editor = this.editor; + var isSeleEmpty = editor.selection.isSelectionEmpty(); + + if (isSeleEmpty) { + // 选区是空的,插入并选中一个“空白” + editor.selection.createEmptyRange(); + } + + // 执行 strikeThrough 命令 + editor.cmd.do('strikeThrough'); + + if (isSeleEmpty) { + // 需要将选取折叠起来 + editor.selection.collapseRange(); + editor.selection.restoreSelection(); + } + }, + + // 试图改变 active 状态 + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + if (editor.cmd.queryCommandState('strikeThrough')) { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + underline-menu +*/ +// 构造函数 +function Underline(editor) { + this.editor = editor; + this.$elem = $('
        \n \n
        '); + this.type = 'click'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Underline.prototype = { + constructor: Underline, + + // 点击事件 + onClick: function onClick(e) { + // 点击菜单将触发这里 + + var editor = this.editor; + var isSeleEmpty = editor.selection.isSelectionEmpty(); + + if (isSeleEmpty) { + // 选区是空的,插入并选中一个“空白” + editor.selection.createEmptyRange(); + } + + // 执行 underline 命令 + editor.cmd.do('underline'); + + if (isSeleEmpty) { + // 需要将选取折叠起来 + editor.selection.collapseRange(); + editor.selection.restoreSelection(); + } + }, + + // 试图改变 active 状态 + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + if (editor.cmd.queryCommandState('underline')) { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + undo-menu +*/ +// 构造函数 +function Undo(editor) { + this.editor = editor; + this.$elem = $('
        \n \n
        '); + this.type = 'click'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Undo.prototype = { + constructor: Undo, + + // 点击事件 + onClick: function onClick(e) { + // 点击菜单将触发这里 + + var editor = this.editor; + + // 执行 undo 命令 + editor.cmd.do('undo'); + } +}; + +/* + menu - list +*/ +// 构造函数 +function List(editor) { + var _this = this; + + this.editor = editor; + this.$elem = $('
        '); + this.type = 'droplist'; + + // 当前是否 active 状态 + this._active = false; + + // 初始化 droplist + this.droplist = new DropList(this, { + width: 120, + $title: $('

        设置列表

        '), + type: 'list', // droplist 以列表形式展示 + list: [{ $elem: $(' 有序列表'), value: 'insertOrderedList' }, { $elem: $(' 无序列表'), value: 'insertUnorderedList' }], + onClick: function onClick(value) { + // 注意 this 是指向当前的 List 对象 + _this._command(value); + } + }); +} + +// 原型 +List.prototype = { + constructor: List, + + // 执行命令 + _command: function _command(value) { + var editor = this.editor; + var $textElem = editor.$textElem; + editor.selection.restoreSelection(); + if (editor.cmd.queryCommandState(value)) { + return; + } + editor.cmd.do(value); + + // 验证列表是否被包裹在

        之内 + var $selectionElem = editor.selection.getSelectionContainerElem(); + if ($selectionElem.getNodeName() === 'LI') { + $selectionElem = $selectionElem.parent(); + } + if (/^ol|ul$/i.test($selectionElem.getNodeName()) === false) { + return; + } + if ($selectionElem.equal($textElem)) { + // 证明是顶级标签,没有被

        包裹 + return; + } + var $parent = $selectionElem.parent(); + if ($parent.equal($textElem)) { + // $parent 是顶级标签,不能删除 + return; + } + + $selectionElem.insertAfter($parent); + $parent.remove(); + }, + + // 试图改变 active 状态 + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + if (editor.cmd.queryCommandState('insertUnOrderedList') || editor.cmd.queryCommandState('insertOrderedList')) { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + menu - justify +*/ +// 构造函数 +function Justify(editor) { + var _this = this; + + this.editor = editor; + this.$elem = $('

        '); + this.type = 'droplist'; + + // 当前是否 active 状态 + this._active = false; + + // 初始化 droplist + this.droplist = new DropList(this, { + width: 100, + $title: $('

        对齐方式

        '), + type: 'list', // droplist 以列表形式展示 + list: [{ $elem: $(' 靠左'), value: 'justifyLeft' }, { $elem: $(' 居中'), value: 'justifyCenter' }, { $elem: $(' 靠右'), value: 'justifyRight' }], + onClick: function onClick(value) { + // 注意 this 是指向当前的 List 对象 + _this._command(value); + } + }); +} + +// 原型 +Justify.prototype = { + constructor: Justify, + + // 执行命令 + _command: function _command(value) { + var editor = this.editor; + editor.cmd.do(value); + } +}; + +/* + menu - Forecolor +*/ +// 构造函数 +function ForeColor(editor) { + var _this = this; + + this.editor = editor; + this.$elem = $('
        '); + this.type = 'droplist'; + + // 获取配置的颜色 + var config = editor.config; + var colors = config.colors || []; + + // 当前是否 active 状态 + this._active = false; + + // 初始化 droplist + this.droplist = new DropList(this, { + width: 120, + $title: $('

        文字颜色

        '), + type: 'inline-block', // droplist 内容以 block 形式展示 + list: colors.map(function (color) { + return { $elem: $(''), value: color }; + }), + onClick: function onClick(value) { + // 注意 this 是指向当前的 ForeColor 对象 + _this._command(value); + } + }); +} + +// 原型 +ForeColor.prototype = { + constructor: ForeColor, + + // 执行命令 + _command: function _command(value) { + var editor = this.editor; + editor.cmd.do('foreColor', value); + } +}; + +/* + menu - BackColor +*/ +// 构造函数 +function BackColor(editor) { + var _this = this; + + this.editor = editor; + this.$elem = $('
        '); + this.type = 'droplist'; + + // 获取配置的颜色 + var config = editor.config; + var colors = config.colors || []; + + // 当前是否 active 状态 + this._active = false; + + // 初始化 droplist + this.droplist = new DropList(this, { + width: 120, + $title: $('

        背景色

        '), + type: 'inline-block', // droplist 内容以 block 形式展示 + list: colors.map(function (color) { + return { $elem: $(''), value: color }; + }), + onClick: function onClick(value) { + // 注意 this 是指向当前的 BackColor 对象 + _this._command(value); + } + }); +} + +// 原型 +BackColor.prototype = { + constructor: BackColor, + + // 执行命令 + _command: function _command(value) { + var editor = this.editor; + editor.cmd.do('backColor', value); + } +}; + +/* + menu - quote +*/ +// 构造函数 +function Quote(editor) { + this.editor = editor; + this.$elem = $('
        \n \n
        '); + this.type = 'click'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Quote.prototype = { + constructor: Quote, + + onClick: function onClick(e) { + var editor = this.editor; + var $selectionElem = editor.selection.getSelectionContainerElem(); + var nodeName = $selectionElem.getNodeName(); + + if (!UA.isIE()) { + if (nodeName === 'BLOCKQUOTE') { + // 撤销 quote + editor.cmd.do('formatBlock', '

        '); + } else { + // 转换为 quote + editor.cmd.do('formatBlock', '

        '); + } + return; + } + + // IE 中不支持 formatBlock
        ,要用其他方式兼容 + var content = void 0, + $targetELem = void 0; + if (nodeName === 'P') { + // 将 P 转换为 quote + content = $selectionElem.text(); + $targetELem = $('
        ' + content + '
        '); + $targetELem.insertAfter($selectionElem); + $selectionElem.remove(); + return; + } + if (nodeName === 'BLOCKQUOTE') { + // 撤销 quote + content = $selectionElem.text(); + $targetELem = $('

        ' + content + '

        '); + $targetELem.insertAfter($selectionElem); + $selectionElem.remove(); + } + }, + + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + var reg = /^BLOCKQUOTE$/i; + var cmdValue = editor.cmd.queryCommandValue('formatBlock'); + if (reg.test(cmdValue)) { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + menu - code +*/ +// 构造函数 +function Code(editor) { + this.editor = editor; + this.$elem = $('
        \n \n
        '); + this.type = 'panel'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Code.prototype = { + constructor: Code, + + onClick: function onClick(e) { + var editor = this.editor; + var $startElem = editor.selection.getSelectionStartElem(); + var $endElem = editor.selection.getSelectionEndElem(); + var isSeleEmpty = editor.selection.isSelectionEmpty(); + var selectionText = editor.selection.getSelectionText(); + var $code = void 0; + + if (!$startElem.equal($endElem)) { + // 跨元素选择,不做处理 + editor.selection.restoreSelection(); + return; + } + if (!isSeleEmpty) { + // 选取不是空,用 包裹即可 + $code = $('' + selectionText + ''); + editor.cmd.do('insertElem', $code); + editor.selection.createRangeByElem($code, false); + editor.selection.restoreSelection(); + return; + } + + // 选取是空,且没有夸元素选择,则插入
        
        +        if (this._active) {
        +            // 选中状态,将编辑内容
        +            this._createPanel($startElem.html());
        +        } else {
        +            // 未选中状态,将创建内容
        +            this._createPanel();
        +        }
        +    },
        +
        +    _createPanel: function _createPanel(value) {
        +        var _this = this;
        +
        +        // value - 要编辑的内容
        +        value = value || '';
        +        var type = !value ? 'new' : 'edit';
        +        var textId = getRandom('texxt');
        +        var btnId = getRandom('btn');
        +
        +        var panel = new Panel(this, {
        +            width: 500,
        +            // 一个 Panel 包含多个 tab
        +            tabs: [{
        +                // 标题
        +                title: '插入代码',
        +                // 模板
        +                tpl: '
        \n \n
        \n \n
        \n
        ', + // 事件绑定 + events: [ + // 插入代码 + { + selector: '#' + btnId, + type: 'click', + fn: function fn() { + var $text = $('#' + textId); + var text = $text.val() || $text.html(); + text = replaceHtmlSymbol(text); + if (type === 'new') { + // 新插入 + _this._insertCode(text); + } else { + // 编辑更新 + _this._updateCode(text); + } + + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }] + } // first tab end + ] // tabs end + }); // new Panel end + + // 显示 panel + panel.show(); + + // 记录属性 + this.panel = panel; + }, + + // 插入代码 + _insertCode: function _insertCode(value) { + var editor = this.editor; + editor.cmd.do('insertHTML', '
        ' + value + '


        '); + }, + + // 更新代码 + _updateCode: function _updateCode(value) { + var editor = this.editor; + var $selectionELem = editor.selection.getSelectionContainerElem(); + if (!$selectionELem) { + return; + } + $selectionELem.html(value); + editor.selection.restoreSelection(); + }, + + // 试图改变 active 状态 + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + var $selectionELem = editor.selection.getSelectionContainerElem(); + if (!$selectionELem) { + return; + } + var $parentElem = $selectionELem.parent(); + if ($selectionELem.getNodeName() === 'CODE' && $parentElem.getNodeName() === 'PRE') { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + menu - emoticon +*/ +// 构造函数 +function Emoticon(editor) { + this.editor = editor; + this.$elem = $('
        \n \n
        '); + this.type = 'panel'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Emoticon.prototype = { + constructor: Emoticon, + + onClick: function onClick() { + this._createPanel(); + }, + + _createPanel: function _createPanel() { + var _this = this; + + var editor = this.editor; + var config = editor.config; + // 获取表情配置 + var emotions = config.emotions || []; + + // 创建表情 dropPanel 的配置 + var tabConfig = []; + emotions.forEach(function (emotData) { + var emotType = emotData.type; + var content = emotData.content || []; + + // 这一组表情最终拼接出来的 html + var faceHtml = ''; + + // emoji 表情 + if (emotType === 'emoji') { + content.forEach(function (item) { + if (item) { + faceHtml += '' + item + ''; + } + }); + } + // 图片表情 + if (emotType === 'image') { + content.forEach(function (item) { + var src = item.src; + var alt = item.alt; + if (src) { + // 加一个 data-w-e 属性,点击图片的时候不再提示编辑图片 + faceHtml += '' + alt + ''; + } + }); + } + + tabConfig.push({ + title: emotData.title, + tpl: '
        ' + faceHtml + '
        ', + events: [{ + selector: 'span.w-e-item', + type: 'click', + fn: function fn(e) { + var target = e.target; + var $target = $(target); + var nodeName = $target.getNodeName(); + + var insertHtml = void 0; + if (nodeName === 'IMG') { + // 插入图片 + insertHtml = $target.parent().html(); + } else { + // 插入 emoji + insertHtml = '' + $target.html() + ''; + } + + _this._insert(insertHtml); + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }] + }); + }); + + var panel = new Panel(this, { + width: 300, + height: 200, + // 一个 Panel 包含多个 tab + tabs: tabConfig + }); + + // 显示 panel + panel.show(); + + // 记录属性 + this.panel = panel; + }, + + // 插入表情 + _insert: function _insert(emotHtml) { + var editor = this.editor; + editor.cmd.do('insertHTML', emotHtml); + } +}; + +/* + menu - table +*/ +// 构造函数 +function Table(editor) { + this.editor = editor; + this.$elem = $('
        '); + this.type = 'panel'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Table.prototype = { + constructor: Table, + + onClick: function onClick() { + if (this._active) { + // 编辑现有表格 + this._createEditPanel(); + } else { + // 插入新表格 + this._createInsertPanel(); + } + }, + + // 创建插入新表格的 panel + _createInsertPanel: function _createInsertPanel() { + var _this = this; + + // 用到的 id + var btnInsertId = getRandom('btn'); + var textRowNum = getRandom('row'); + var textColNum = getRandom('col'); + + var panel = new Panel(this, { + width: 250, + // panel 包含多个 tab + tabs: [{ + // 标题 + title: '插入表格', + // 模板 + tpl: '
        \n

        \n \u521B\u5EFA\n \n \u884C\n \n \u5217\u7684\u8868\u683C\n

        \n
        \n \n
        \n
        ', + // 事件绑定 + events: [{ + // 点击按钮,插入表格 + selector: '#' + btnInsertId, + type: 'click', + fn: function fn() { + var rowNum = parseInt($('#' + textRowNum).val()); + var colNum = parseInt($('#' + textColNum).val()); + + if (rowNum && colNum && rowNum > 0 && colNum > 0) { + // form 数据有效 + _this._insert(rowNum, colNum); + } + + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }] + } // first tab end + ] // tabs end + }); // panel end + + // 展示 panel + panel.show(); + + // 记录属性 + this.panel = panel; + }, + + // 插入表格 + _insert: function _insert(rowNum, colNum) { + // 拼接 table 模板 + var r = void 0, + c = void 0; + var html = ''; + for (r = 0; r < rowNum; r++) { + html += ''; + if (r === 0) { + for (c = 0; c < colNum; c++) { + html += ''; + } + } else { + for (c = 0; c < colNum; c++) { + html += ''; + } + } + html += ''; + } + html += '
          


        '; + + // 执行命令 + var editor = this.editor; + editor.cmd.do('insertHTML', html); + + // 防止 firefox 下出现 resize 的控制点 + editor.cmd.do('enableObjectResizing', false); + editor.cmd.do('enableInlineTableEditing', false); + }, + + // 创建编辑表格的 panel + _createEditPanel: function _createEditPanel() { + var _this2 = this; + + // 可用的 id + var addRowBtnId = getRandom('add-row'); + var addColBtnId = getRandom('add-col'); + var delRowBtnId = getRandom('del-row'); + var delColBtnId = getRandom('del-col'); + var delTableBtnId = getRandom('del-table'); + + // 创建 panel 对象 + var panel = new Panel(this, { + width: 320, + // panel 包含多个 tab + tabs: [{ + // 标题 + title: '编辑表格', + // 模板 + tpl: '
        \n
        \n \n \n \n \n
        \n
        \n \n \n
        ', + // 事件绑定 + events: [{ + // 增加行 + selector: '#' + addRowBtnId, + type: 'click', + fn: function fn() { + _this2._addRow(); + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }, { + // 增加列 + selector: '#' + addColBtnId, + type: 'click', + fn: function fn() { + _this2._addCol(); + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }, { + // 删除行 + selector: '#' + delRowBtnId, + type: 'click', + fn: function fn() { + _this2._delRow(); + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }, { + // 删除列 + selector: '#' + delColBtnId, + type: 'click', + fn: function fn() { + _this2._delCol(); + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }, { + // 删除表格 + selector: '#' + delTableBtnId, + type: 'click', + fn: function fn() { + _this2._delTable(); + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }] + }] + }); + // 显示 panel + panel.show(); + }, + + // 获取选中的单元格的位置信息 + _getLocationData: function _getLocationData() { + var result = {}; + var editor = this.editor; + var $selectionELem = editor.selection.getSelectionContainerElem(); + if (!$selectionELem) { + return; + } + var nodeName = $selectionELem.getNodeName(); + if (nodeName !== 'TD' && nodeName !== 'TH') { + return; + } + + // 获取 td index + var $tr = $selectionELem.parent(); + var $tds = $tr.children(); + var tdLength = $tds.length; + $tds.forEach(function (td, index) { + if (td === $selectionELem[0]) { + // 记录并跳出循环 + result.td = { + index: index, + elem: td, + length: tdLength + }; + return false; + } + }); + + // 获取 tr index + var $tbody = $tr.parent(); + var $trs = $tbody.children(); + var trLength = $trs.length; + $trs.forEach(function (tr, index) { + if (tr === $tr[0]) { + // 记录并跳出循环 + result.tr = { + index: index, + elem: tr, + length: trLength + }; + return false; + } + }); + + // 返回结果 + return result; + }, + + // 增加行 + _addRow: function _addRow() { + // 获取当前单元格的位置信息 + var locationData = this._getLocationData(); + if (!locationData) { + return; + } + var trData = locationData.tr; + var $currentTr = $(trData.elem); + var tdData = locationData.td; + var tdLength = tdData.length; + + // 拼接即将插入的字符串 + var newTr = document.createElement('tr'); + var tpl = '', + i = void 0; + for (i = 0; i < tdLength; i++) { + tpl += ' '; + } + newTr.innerHTML = tpl; + // 插入 + $(newTr).insertAfter($currentTr); + }, + + // 增加列 + _addCol: function _addCol() { + // 获取当前单元格的位置信息 + var locationData = this._getLocationData(); + if (!locationData) { + return; + } + var trData = locationData.tr; + var tdData = locationData.td; + var tdIndex = tdData.index; + var $currentTr = $(trData.elem); + var $trParent = $currentTr.parent(); + var $trs = $trParent.children(); + + // 遍历所有行 + $trs.forEach(function (tr) { + var $tr = $(tr); + var $tds = $tr.children(); + var $currentTd = $tds.get(tdIndex); + var name = $currentTd.getNodeName().toLowerCase(); + + // new 一个 td,并插入 + var newTd = document.createElement(name); + $(newTd).insertAfter($currentTd); + }); + }, + + // 删除行 + _delRow: function _delRow() { + // 获取当前单元格的位置信息 + var locationData = this._getLocationData(); + if (!locationData) { + return; + } + var trData = locationData.tr; + var $currentTr = $(trData.elem); + $currentTr.remove(); + }, + + // 删除列 + _delCol: function _delCol() { + // 获取当前单元格的位置信息 + var locationData = this._getLocationData(); + if (!locationData) { + return; + } + var trData = locationData.tr; + var tdData = locationData.td; + var tdIndex = tdData.index; + var $currentTr = $(trData.elem); + var $trParent = $currentTr.parent(); + var $trs = $trParent.children(); + + // 遍历所有行 + $trs.forEach(function (tr) { + var $tr = $(tr); + var $tds = $tr.children(); + var $currentTd = $tds.get(tdIndex); + // 删除 + $currentTd.remove(); + }); + }, + + // 删除表格 + _delTable: function _delTable() { + var editor = this.editor; + var $selectionELem = editor.selection.getSelectionContainerElem(); + if (!$selectionELem) { + return; + } + var $table = $selectionELem.parentUntil('table'); + if (!$table) { + return; + } + $table.remove(); + }, + + // 试图改变 active 状态 + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + var $selectionELem = editor.selection.getSelectionContainerElem(); + if (!$selectionELem) { + return; + } + var nodeName = $selectionELem.getNodeName(); + if (nodeName === 'TD' || nodeName === 'TH') { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + menu - video +*/ +// 构造函数 +function Video(editor) { + this.editor = editor; + this.$elem = $('
        '); + this.type = 'panel'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Video.prototype = { + constructor: Video, + + onClick: function onClick() { + this._createPanel(); + }, + + _createPanel: function _createPanel() { + var _this = this; + + // 创建 id + var textValId = getRandom('text-val'); + var btnId = getRandom('btn'); + + // 创建 panel + var panel = new Panel(this, { + width: 350, + // 一个 panel 多个 tab + tabs: [{ + // 标题 + title: '插入视频', + // 模板 + tpl: '
        \n \n
        \n \n
        \n
        ', + // 事件绑定 + events: [{ + selector: '#' + btnId, + type: 'click', + fn: function fn() { + var $text = $('#' + textValId); + var val = $text.val().trim(); + + // 测试用视频地址 + // + + if (val) { + // 插入视频 + _this._insert(val); + } + + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }] + } // first tab end + ] // tabs end + }); // panel end + + // 显示 panel + panel.show(); + + // 记录属性 + this.panel = panel; + }, + + // 插入视频 + _insert: function _insert(val) { + var editor = this.editor; + editor.cmd.do('insertHTML', val + '


        '); + } +}; + +/* + menu - img +*/ +// 构造函数 +function Image(editor) { + this.editor = editor; + var imgMenuId = getRandom('w-e-img'); + this.$elem = $('
        '); + editor.imgMenuId = imgMenuId; + this.type = 'panel'; + + // 当前是否 active 状态 + this._active = false; +} + +// 原型 +Image.prototype = { + constructor: Image, + + onClick: function onClick() { + var editor = this.editor; + var config = editor.config; + if (config.qiniu) { + return; + } + if (this._active) { + this._createEditPanel(); + } else { + this._createInsertPanel(); + } + }, + + _createEditPanel: function _createEditPanel() { + var editor = this.editor; + + // id + var width30 = getRandom('width-30'); + var width50 = getRandom('width-50'); + var width100 = getRandom('width-100'); + var delBtn = getRandom('del-btn'); + + // tab 配置 + var tabsConfig = [{ + title: '编辑图片', + tpl: '
        \n
        \n \u6700\u5927\u5BBD\u5EA6\uFF1A\n \n \n \n
        \n
        \n \n \n
        ', + events: [{ + selector: '#' + width30, + type: 'click', + fn: function fn() { + var $img = editor._selectedImg; + if ($img) { + $img.css('max-width', '30%'); + } + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }, { + selector: '#' + width50, + type: 'click', + fn: function fn() { + var $img = editor._selectedImg; + if ($img) { + $img.css('max-width', '50%'); + } + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }, { + selector: '#' + width100, + type: 'click', + fn: function fn() { + var $img = editor._selectedImg; + if ($img) { + $img.css('max-width', '100%'); + } + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }, { + selector: '#' + delBtn, + type: 'click', + fn: function fn() { + var $img = editor._selectedImg; + if ($img) { + $img.remove(); + } + // 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭 + return true; + } + }] + }]; + + // 创建 panel 并显示 + var panel = new Panel(this, { + width: 300, + tabs: tabsConfig + }); + panel.show(); + + // 记录属性 + this.panel = panel; + }, + + _createInsertPanel: function _createInsertPanel() { + var editor = this.editor; + var uploadImg = editor.uploadImg; + var config = editor.config; + + // id + var upTriggerId = getRandom('up-trigger'); + var upFileId = getRandom('up-file'); + var linkUrlId = getRandom('link-url'); + var linkBtnId = getRandom('link-btn'); + + // tabs 的配置 + var tabsConfig = [{ + title: '上传图片', + tpl: '
        \n
        \n \n
        \n
        \n \n
        \n
        ', + events: [{ + // 触发选择图片 + selector: '#' + upTriggerId, + type: 'click', + fn: function fn() { + var $file = $('#' + upFileId); + var fileElem = $file[0]; + if (fileElem) { + fileElem.click(); + } else { + // 返回 true 可关闭 panel + return true; + } + } + }, { + // 选择图片完毕 + selector: '#' + upFileId, + type: 'change', + fn: function fn() { + var $file = $('#' + upFileId); + var fileElem = $file[0]; + if (!fileElem) { + // 返回 true 可关闭 panel + return true; + } + + // 获取选中的 file 对象列表 + var fileList = fileElem.files; + if (fileList.length) { + uploadImg.uploadImg(fileList); + } + + // 返回 true 可关闭 panel + return true; + } + }] + }, // first tab end + { + title: '网络图片', + tpl: '
        \n \n
        \n \n
        \n
        ', + events: [{ + selector: '#' + linkBtnId, + type: 'click', + fn: function fn() { + var $linkUrl = $('#' + linkUrlId); + var url = $linkUrl.val().trim(); + + if (url) { + uploadImg.insertLinkImg(url); + } + + // 返回 true 表示函数执行结束之后关闭 panel + return true; + } + }] + } // second tab end + ]; // tabs end + + // 判断 tabs 的显示 + var tabsConfigResult = []; + if ((config.uploadImgShowBase64 || config.uploadImgServer || config.customUploadImg) && window.FileReader) { + // 显示“上传图片” + tabsConfigResult.push(tabsConfig[0]); + } + if (config.showLinkImg) { + // 显示“网络图片” + tabsConfigResult.push(tabsConfig[1]); + } + + // 创建 panel 并显示 + var panel = new Panel(this, { + width: 300, + tabs: tabsConfigResult + }); + panel.show(); + + // 记录属性 + this.panel = panel; + }, + + // 试图改变 active 状态 + tryChangeActive: function tryChangeActive(e) { + var editor = this.editor; + var $elem = this.$elem; + if (editor._selectedImg) { + this._active = true; + $elem.addClass('w-e-active'); + } else { + this._active = false; + $elem.removeClass('w-e-active'); + } + } +}; + +/* + 所有菜单的汇总 +*/ + +// 存储菜单的构造函数 +var MenuConstructors = {}; + +MenuConstructors.bold = Bold; + +MenuConstructors.head = Head; + +MenuConstructors.fontSize = FontSize; + +MenuConstructors.fontName = FontName; + +MenuConstructors.link = Link; + +MenuConstructors.italic = Italic; + +MenuConstructors.redo = Redo; + +MenuConstructors.strikeThrough = StrikeThrough; + +MenuConstructors.underline = Underline; + +MenuConstructors.undo = Undo; + +MenuConstructors.list = List; + +MenuConstructors.justify = Justify; + +MenuConstructors.foreColor = ForeColor; + +MenuConstructors.backColor = BackColor; + +MenuConstructors.quote = Quote; + +MenuConstructors.code = Code; + +MenuConstructors.emoticon = Emoticon; + +MenuConstructors.table = Table; + +MenuConstructors.video = Video; + +MenuConstructors.image = Image; + +/* + 菜单集合 +*/ +// 构造函数 +function Menus(editor) { + this.editor = editor; + this.menus = {}; +} + +// 修改原型 +Menus.prototype = { + constructor: Menus, + + // 初始化菜单 + init: function init() { + var _this = this; + + var editor = this.editor; + var config = editor.config || {}; + var configMenus = config.menus || []; // 获取配置中的菜单 + + // 根据配置信息,创建菜单 + configMenus.forEach(function (menuKey) { + var MenuConstructor = MenuConstructors[menuKey]; + if (MenuConstructor && typeof MenuConstructor === 'function') { + // 创建单个菜单 + _this.menus[menuKey] = new MenuConstructor(editor); + } + }); + + // 添加到菜单栏 + this._addToToolbar(); + + // 绑定事件 + this._bindEvent(); + }, + + // 添加到菜单栏 + _addToToolbar: function _addToToolbar() { + var editor = this.editor; + var $toolbarElem = editor.$toolbarElem; + var menus = this.menus; + var config = editor.config; + // config.zIndex 是配置的编辑区域的 z-index,菜单的 z-index 得在其基础上 +1 + var zIndex = config.zIndex + 1; + objForEach(menus, function (key, menu) { + var $elem = menu.$elem; + if ($elem) { + // 设置 z-index + $elem.css('z-index', zIndex); + $toolbarElem.append($elem); + } + }); + }, + + // 绑定菜单 click mouseenter 事件 + _bindEvent: function _bindEvent() { + var menus = this.menus; + var editor = this.editor; + objForEach(menus, function (key, menu) { + var type = menu.type; + if (!type) { + return; + } + var $elem = menu.$elem; + var droplist = menu.droplist; + var panel = menu.panel; + + // 点击类型,例如 bold + if (type === 'click' && menu.onClick) { + $elem.on('click', function (e) { + if (editor.selection.getRange() == null) { + return; + } + menu.onClick(e); + }); + } + + // 下拉框,例如 head + if (type === 'droplist' && droplist) { + $elem.on('mouseenter', function (e) { + if (editor.selection.getRange() == null) { + return; + } + // 显示 + droplist.showTimeoutId = setTimeout(function () { + droplist.show(); + }, 200); + }).on('mouseleave', function (e) { + // 隐藏 + droplist.hideTimeoutId = setTimeout(function () { + droplist.hide(); + }, 0); + }); + } + + // 弹框类型,例如 link + if (type === 'panel' && menu.onClick) { + $elem.on('click', function (e) { + e.stopPropagation(); + if (editor.selection.getRange() == null) { + return; + } + // 在自定义事件中显示 panel + menu.onClick(e); + }); + } + }); + }, + + // 尝试修改菜单状态 + changeActive: function changeActive() { + var menus = this.menus; + objForEach(menus, function (key, menu) { + if (menu.tryChangeActive) { + setTimeout(function () { + menu.tryChangeActive(); + }, 100); + } + }); + } +}; + +/* + 粘贴信息的处理 +*/ + +// 获取粘贴的纯文本 +function getPasteText(e) { + var clipboardData = e.clipboardData || e.originalEvent && e.originalEvent.clipboardData; + var pasteText = void 0; + if (clipboardData == null) { + pasteText = window.clipboardData && window.clipboardData.getData('text'); + } else { + pasteText = clipboardData.getData('text/plain'); + } + + return replaceHtmlSymbol(pasteText); +} + +// 获取粘贴的html +function getPasteHtml(e, filterStyle, ignoreImg) { + var clipboardData = e.clipboardData || e.originalEvent && e.originalEvent.clipboardData; + var pasteText = void 0, + pasteHtml = void 0; + if (clipboardData == null) { + pasteText = window.clipboardData && window.clipboardData.getData('text'); + } else { + pasteText = clipboardData.getData('text/plain'); + pasteHtml = clipboardData.getData('text/html'); + } + if (!pasteHtml && pasteText) { + pasteHtml = '

        ' + replaceHtmlSymbol(pasteText) + '

        '; + } + if (!pasteHtml) { + return; + } + + // 过滤word中状态过来的无用字符 + var docSplitHtml = pasteHtml.split(''); + if (docSplitHtml.length === 2) { + pasteHtml = docSplitHtml[0]; + } + + // 过滤无用标签 + pasteHtml = pasteHtml.replace(/<(meta|script|link).+?>/igm, ''); + // 去掉注释 + pasteHtml = pasteHtml.replace(//mg, ''); + // 过滤 data-xxx 属性 + pasteHtml = pasteHtml.replace(/\s?data-.+?=('|").+?('|")/igm, ''); + + if (ignoreImg) { + // 忽略图片 + pasteHtml = pasteHtml.replace(//igm, ''); + } + + if (filterStyle) { + // 过滤样式 + pasteHtml = pasteHtml.replace(/\s?(class|style)=('|").*?('|")/igm, ''); + } else { + // 保留样式 + pasteHtml = pasteHtml.replace(/\s?class=('|").*?('|")/igm, ''); + } + + return pasteHtml; +} + +// 获取粘贴的图片文件 +function getPasteImgs(e) { + var result = []; + var txt = getPasteText(e); + if (txt) { + // 有文字,就忽略图片 + return result; + } + + var clipboardData = e.clipboardData || e.originalEvent && e.originalEvent.clipboardData || {}; + var items = clipboardData.items; + if (!items) { + return result; + } + + objForEach(items, function (key, value) { + var type = value.type; + if (/image/i.test(type)) { + result.push(value.getAsFile()); + } + }); + + return result; +} + +/* + 编辑区域 +*/ + +// 获取一个 elem.childNodes 的 JSON 数据 +function getChildrenJSON($elem) { + var result = []; + var $children = $elem.childNodes() || []; // 注意 childNodes() 可以获取文本节点 + $children.forEach(function (curElem) { + var elemResult = void 0; + var nodeType = curElem.nodeType; + + // 文本节点 + if (nodeType === 3) { + elemResult = curElem.textContent; + elemResult = replaceHtmlSymbol(elemResult); + } + + // 普通 DOM 节点 + if (nodeType === 1) { + elemResult = {}; + + // tag + elemResult.tag = curElem.nodeName.toLowerCase(); + // attr + var attrData = []; + var attrList = curElem.attributes || {}; + var attrListLength = attrList.length || 0; + for (var i = 0; i < attrListLength; i++) { + var attr = attrList[i]; + attrData.push({ + name: attr.name, + value: attr.value + }); + } + elemResult.attrs = attrData; + // children(递归) + elemResult.children = getChildrenJSON($(curElem)); + } + + result.push(elemResult); + }); + return result; +} + +// 构造函数 +function Text(editor) { + this.editor = editor; +} + +// 修改原型 +Text.prototype = { + constructor: Text, + + // 初始化 + init: function init() { + // 绑定事件 + this._bindEvent(); + }, + + // 清空内容 + clear: function clear() { + this.html('


        '); + }, + + // 获取 设置 html + html: function html(val) { + var editor = this.editor; + var $textElem = editor.$textElem; + var html = void 0; + if (val == null) { + html = $textElem.html(); + // 未选中任何内容的时候点击“加粗”或者“斜体”等按钮,就得需要一个空的占位符 ​ ,这里替换掉 + html = html.replace(/\u200b/gm, ''); + return html; + } else { + $textElem.html(val); + + // 初始化选取,将光标定位到内容尾部 + editor.initSelection(); + } + }, + + // 获取 JSON + getJSON: function getJSON() { + var editor = this.editor; + var $textElem = editor.$textElem; + return getChildrenJSON($textElem); + }, + + // 获取 设置 text + text: function text(val) { + var editor = this.editor; + var $textElem = editor.$textElem; + var text = void 0; + if (val == null) { + text = $textElem.text(); + // 未选中任何内容的时候点击“加粗”或者“斜体”等按钮,就得需要一个空的占位符 ​ ,这里替换掉 + text = text.replace(/\u200b/gm, ''); + return text; + } else { + $textElem.text('

        ' + val + '

        '); + + // 初始化选取,将光标定位到内容尾部 + editor.initSelection(); + } + }, + + // 追加内容 + append: function append(html) { + var editor = this.editor; + var $textElem = editor.$textElem; + $textElem.append($(html)); + + // 初始化选取,将光标定位到内容尾部 + editor.initSelection(); + }, + + // 绑定事件 + _bindEvent: function _bindEvent() { + // 实时保存选取 + this._saveRangeRealTime(); + + // 按回车建时的特殊处理 + this._enterKeyHandle(); + + // 清空时保留


        + this._clearHandle(); + + // 粘贴事件(粘贴文字,粘贴图片) + this._pasteHandle(); + + // tab 特殊处理 + this._tabHandle(); + + // img 点击 + this._imgHandle(); + + // 拖拽事件 + this._dragHandle(); + }, + + // 实时保存选取 + _saveRangeRealTime: function _saveRangeRealTime() { + var editor = this.editor; + var $textElem = editor.$textElem; + + // 保存当前的选区 + function saveRange(e) { + // 随时保存选区 + editor.selection.saveRange(); + // 更新按钮 ative 状态 + editor.menus.changeActive(); + } + // 按键后保存 + $textElem.on('keyup', saveRange); + $textElem.on('mousedown', function (e) { + // mousedown 状态下,鼠标滑动到编辑区域外面,也需要保存选区 + $textElem.on('mouseleave', saveRange); + }); + $textElem.on('mouseup', function (e) { + saveRange(); + // 在编辑器区域之内完成点击,取消鼠标滑动到编辑区外面的事件 + $textElem.off('mouseleave', saveRange); + }); + }, + + // 按回车键时的特殊处理 + _enterKeyHandle: function _enterKeyHandle() { + var editor = this.editor; + var $textElem = editor.$textElem; + + function insertEmptyP($selectionElem) { + var $p = $('


        '); + $p.insertBefore($selectionElem); + editor.selection.createRangeByElem($p, true); + editor.selection.restoreSelection(); + $selectionElem.remove(); + } + + // 将回车之后生成的非

        的顶级标签,改为

        + function pHandle(e) { + var $selectionElem = editor.selection.getSelectionContainerElem(); + var $parentElem = $selectionElem.parent(); + + if ($parentElem.html() === '
        ') { + // 回车之前光标所在一个

        .....

        ,忽然回车生成一个空的


        + // 而且继续回车跳不出去,因此只能特殊处理 + insertEmptyP($selectionElem); + return; + } + + if (!$parentElem.equal($textElem)) { + // 不是顶级标签 + return; + } + + var nodeName = $selectionElem.getNodeName(); + if (nodeName === 'P') { + // 当前的标签是 P ,不用做处理 + return; + } + + if ($selectionElem.text()) { + // 有内容,不做处理 + return; + } + + // 插入

        ,并将选取定位到

        ,删除当前标签 + insertEmptyP($selectionElem); + } + + $textElem.on('keyup', function (e) { + if (e.keyCode !== 13) { + // 不是回车键 + return; + } + // 将回车之后生成的非

        的顶级标签,改为

        + pHandle(e); + }); + + //

        回车时 特殊处理 + function codeHandle(e) { + var $selectionElem = editor.selection.getSelectionContainerElem(); + if (!$selectionElem) { + return; + } + var $parentElem = $selectionElem.parent(); + var selectionNodeName = $selectionElem.getNodeName(); + var parentNodeName = $parentElem.getNodeName(); + + if (selectionNodeName !== 'CODE' || parentNodeName !== 'PRE') { + // 不符合要求 忽略 + return; + } + + if (!editor.cmd.queryCommandSupported('insertHTML')) { + // 必须原生支持 insertHTML 命令 + return; + } + + // 处理:光标定位到代码末尾,联系点击两次回车,即跳出代码块 + if (editor._willBreakCode === true) { + // 此时可以跳出代码块 + // 插入

        ,并将选取定位到

        + var $p = $('


        '); + $p.insertAfter($parentElem); + editor.selection.createRangeByElem($p, true); + editor.selection.restoreSelection(); + + // 修改状态 + editor._willBreakCode = false; + + e.preventDefault(); + return; + } + + var _startOffset = editor.selection.getRange().startOffset; + + // 处理:回车时,不能插入
        而是插入 \n ,因为是在 pre 标签里面 + editor.cmd.do('insertHTML', '\n'); + editor.selection.saveRange(); + if (editor.selection.getRange().startOffset === _startOffset) { + // 没起作用,再来一遍 + editor.cmd.do('insertHTML', '\n'); + } + + var codeLength = $selectionElem.html().length; + if (editor.selection.getRange().startOffset + 1 === codeLength) { + // 说明光标在代码最后的位置,执行了回车操作 + // 记录下来,以便下次回车时候跳出 code + editor._willBreakCode = true; + } + + // 阻止默认行为 + e.preventDefault(); + } + + $textElem.on('keydown', function (e) { + if (e.keyCode !== 13) { + // 不是回车键 + // 取消即将跳转代码块的记录 + editor._willBreakCode = false; + return; + } + //
        回车时 特殊处理 + codeHandle(e); + }); + }, + + // 清空时保留


        + _clearHandle: function _clearHandle() { + var editor = this.editor; + var $textElem = editor.$textElem; + + $textElem.on('keydown', function (e) { + if (e.keyCode !== 8) { + return; + } + var txtHtml = $textElem.html().toLowerCase().trim(); + if (txtHtml === '


        ') { + // 最后剩下一个空行,就不再删除了 + e.preventDefault(); + return; + } + }); + + $textElem.on('keyup', function (e) { + if (e.keyCode !== 8) { + return; + } + var $p = void 0; + var txtHtml = $textElem.html().toLowerCase().trim(); + + // firefox 时用 txtHtml === '
        ' 判断,其他用 !txtHtml 判断 + if (!txtHtml || txtHtml === '
        ') { + // 内容空了 + $p = $('


        '); + $textElem.html(''); // 一定要先清空,否则在 firefox 下有问题 + $textElem.append($p); + editor.selection.createRangeByElem($p, false, true); + editor.selection.restoreSelection(); + } + }); + }, + + // 粘贴事件(粘贴文字 粘贴图片) + _pasteHandle: function _pasteHandle() { + var editor = this.editor; + var config = editor.config; + var pasteFilterStyle = config.pasteFilterStyle; + var pasteTextHandle = config.pasteTextHandle; + var ignoreImg = config.pasteIgnoreImg; + var $textElem = editor.$textElem; + + // 粘贴图片、文本的事件,每次只能执行一个 + // 判断该次粘贴事件是否可以执行 + var pasteTime = 0; + function canDo() { + var now = Date.now(); + var flag = false; + if (now - pasteTime >= 100) { + // 间隔大于 100 ms ,可以执行 + flag = true; + } + pasteTime = now; + return flag; + } + function resetTime() { + pasteTime = 0; + } + + // 粘贴文字 + $textElem.on('paste', function (e) { + if (UA.isIE()) { + return; + } else { + // 阻止默认行为,使用 execCommand 的粘贴命令 + e.preventDefault(); + } + + // 粘贴图片和文本,只能同时使用一个 + if (!canDo()) { + return; + } + + // 获取粘贴的文字 + var pasteHtml = getPasteHtml(e, pasteFilterStyle, ignoreImg); + var pasteText = getPasteText(e); + pasteText = pasteText.replace(/\n/gm, '
        '); + + var $selectionElem = editor.selection.getSelectionContainerElem(); + if (!$selectionElem) { + return; + } + var nodeName = $selectionElem.getNodeName(); + + // code 中只能粘贴纯文本 + if (nodeName === 'CODE' || nodeName === 'PRE') { + if (pasteTextHandle && isFunction(pasteTextHandle)) { + // 用户自定义过滤处理粘贴内容 + pasteText = '' + (pasteTextHandle(pasteText) || ''); + } + editor.cmd.do('insertHTML', '

        ' + pasteText + '

        '); + return; + } + + // 先放开注释,有问题再追查 ———— + // // 表格中忽略,可能会出现异常问题 + // if (nodeName === 'TD' || nodeName === 'TH') { + // return + // } + + if (!pasteHtml) { + // 没有内容,可继续执行下面的图片粘贴 + resetTime(); + return; + } + try { + // firefox 中,获取的 pasteHtml 可能是没有
          包裹的
        • + // 因此执行 insertHTML 会报错 + if (pasteTextHandle && isFunction(pasteTextHandle)) { + // 用户自定义过滤处理粘贴内容 + pasteHtml = '' + (pasteTextHandle(pasteHtml) || ''); + } + editor.cmd.do('insertHTML', pasteHtml); + } catch (ex) { + // 此时使用 pasteText 来兼容一下 + if (pasteTextHandle && isFunction(pasteTextHandle)) { + // 用户自定义过滤处理粘贴内容 + pasteText = '' + (pasteTextHandle(pasteText) || ''); + } + editor.cmd.do('insertHTML', '

          ' + pasteText + '

          '); + } + }); + + // 粘贴图片 + $textElem.on('paste', function (e) { + if (UA.isIE()) { + return; + } else { + e.preventDefault(); + } + + // 粘贴图片和文本,只能同时使用一个 + if (!canDo()) { + return; + } + + // 获取粘贴的图片 + var pasteFiles = getPasteImgs(e); + if (!pasteFiles || !pasteFiles.length) { + return; + } + + // 获取当前的元素 + var $selectionElem = editor.selection.getSelectionContainerElem(); + if (!$selectionElem) { + return; + } + var nodeName = $selectionElem.getNodeName(); + + // code 中粘贴忽略 + if (nodeName === 'CODE' || nodeName === 'PRE') { + return; + } + + // 上传图片 + var uploadImg = editor.uploadImg; + uploadImg.uploadImg(pasteFiles); + }); + }, + + // tab 特殊处理 + _tabHandle: function _tabHandle() { + var editor = this.editor; + var $textElem = editor.$textElem; + + $textElem.on('keydown', function (e) { + if (e.keyCode !== 9) { + return; + } + if (!editor.cmd.queryCommandSupported('insertHTML')) { + // 必须原生支持 insertHTML 命令 + return; + } + var $selectionElem = editor.selection.getSelectionContainerElem(); + if (!$selectionElem) { + return; + } + var $parentElem = $selectionElem.parent(); + var selectionNodeName = $selectionElem.getNodeName(); + var parentNodeName = $parentElem.getNodeName(); + + if (selectionNodeName === 'CODE' && parentNodeName === 'PRE') { + //
           里面
          +                editor.cmd.do('insertHTML', '    ');
          +            } else {
          +                // 普通文字
          +                editor.cmd.do('insertHTML', '    ');
          +            }
          +
          +            e.preventDefault();
          +        });
          +    },
          +
          +    // img 点击
          +    _imgHandle: function _imgHandle() {
          +        var editor = this.editor;
          +        var $textElem = editor.$textElem;
          +
          +        // 为图片增加 selected 样式
          +        $textElem.on('click', 'img', function (e) {
          +            var img = this;
          +            var $img = $(img);
          +
          +            if ($img.attr('data-w-e') === '1') {
          +                // 是表情图片,忽略
          +                return;
          +            }
          +
          +            // 记录当前点击过的图片
          +            editor._selectedImg = $img;
          +
          +            // 修改选区并 restore ,防止用户此时点击退格键,会删除其他内容
          +            editor.selection.createRangeByElem($img);
          +            editor.selection.restoreSelection();
          +        });
          +
          +        // 去掉图片的 selected 样式
          +        $textElem.on('click  keyup', function (e) {
          +            if (e.target.matches('img')) {
          +                // 点击的是图片,忽略
          +                return;
          +            }
          +            // 删除记录
          +            editor._selectedImg = null;
          +        });
          +    },
          +
          +    // 拖拽事件
          +    _dragHandle: function _dragHandle() {
          +        var editor = this.editor;
          +
          +        // 禁用 document 拖拽事件
          +        var $document = $(document);
          +        $document.on('dragleave drop dragenter dragover', function (e) {
          +            e.preventDefault();
          +        });
          +
          +        // 添加编辑区域拖拽事件
          +        var $textElem = editor.$textElem;
          +        $textElem.on('drop', function (e) {
          +            e.preventDefault();
          +            var files = e.dataTransfer && e.dataTransfer.files;
          +            if (!files || !files.length) {
          +                return;
          +            }
          +
          +            // 上传图片
          +            var uploadImg = editor.uploadImg;
          +            uploadImg.uploadImg(files);
          +        });
          +    }
          +};
          +
          +/*
          +    命令,封装 document.execCommand
          +*/
          +
          +// 构造函数
          +function Command(editor) {
          +    this.editor = editor;
          +}
          +
          +// 修改原型
          +Command.prototype = {
          +    constructor: Command,
          +
          +    // 执行命令
          +    do: function _do(name, value) {
          +        var editor = this.editor;
          +
          +        // 使用 styleWithCSS
          +        if (!editor._useStyleWithCSS) {
          +            document.execCommand('styleWithCSS', null, true);
          +            editor._useStyleWithCSS = true;
          +        }
          +
          +        // 如果无选区,忽略
          +        if (!editor.selection.getRange()) {
          +            return;
          +        }
          +
          +        // 恢复选取
          +        editor.selection.restoreSelection();
          +
          +        // 执行
          +        var _name = '_' + name;
          +        if (this[_name]) {
          +            // 有自定义事件
          +            this[_name](value);
          +        } else {
          +            // 默认 command
          +            this._execCommand(name, value);
          +        }
          +
          +        // 修改菜单状态
          +        editor.menus.changeActive();
          +
          +        // 最后,恢复选取保证光标在原来的位置闪烁
          +        editor.selection.saveRange();
          +        editor.selection.restoreSelection();
          +
          +        // 触发 onchange
          +        editor.change && editor.change();
          +    },
          +
          +    // 自定义 insertHTML 事件
          +    _insertHTML: function _insertHTML(html) {
          +        var editor = this.editor;
          +        var range = editor.selection.getRange();
          +
          +        if (this.queryCommandSupported('insertHTML')) {
          +            // W3C
          +            this._execCommand('insertHTML', html);
          +        } else if (range.insertNode) {
          +            // IE
          +            range.deleteContents();
          +            range.insertNode($(html)[0]);
          +        } else if (range.pasteHTML) {
          +            // IE <= 10
          +            range.pasteHTML(html);
          +        }
          +    },
          +
          +    // 插入 elem
          +    _insertElem: function _insertElem($elem) {
          +        var editor = this.editor;
          +        var range = editor.selection.getRange();
          +
          +        if (range.insertNode) {
          +            range.deleteContents();
          +            range.insertNode($elem[0]);
          +        }
          +    },
          +
          +    // 封装 execCommand
          +    _execCommand: function _execCommand(name, value) {
          +        document.execCommand(name, false, value);
          +    },
          +
          +    // 封装 document.queryCommandValue
          +    queryCommandValue: function queryCommandValue(name) {
          +        return document.queryCommandValue(name);
          +    },
          +
          +    // 封装 document.queryCommandState
          +    queryCommandState: function queryCommandState(name) {
          +        return document.queryCommandState(name);
          +    },
          +
          +    // 封装 document.queryCommandSupported
          +    queryCommandSupported: function queryCommandSupported(name) {
          +        return document.queryCommandSupported(name);
          +    }
          +};
          +
          +/*
          +    selection range API
          +*/
          +
          +// 构造函数
          +function API(editor) {
          +    this.editor = editor;
          +    this._currentRange = null;
          +}
          +
          +// 修改原型
          +API.prototype = {
          +    constructor: API,
          +
          +    // 获取 range 对象
          +    getRange: function getRange() {
          +        return this._currentRange;
          +    },
          +
          +    // 保存选区
          +    saveRange: function saveRange(_range) {
          +        if (_range) {
          +            // 保存已有选区
          +            this._currentRange = _range;
          +            return;
          +        }
          +
          +        // 获取当前的选区
          +        var selection = window.getSelection();
          +        if (selection.rangeCount === 0) {
          +            return;
          +        }
          +        var range = selection.getRangeAt(0);
          +
          +        // 判断选区内容是否在编辑内容之内
          +        var $containerElem = this.getSelectionContainerElem(range);
          +        if (!$containerElem) {
          +            return;
          +        }
          +
          +        // 判断选区内容是否在不可编辑区域之内
          +        if ($containerElem.attr('contenteditable') === 'false' || $containerElem.parentUntil('[contenteditable=false]')) {
          +            return;
          +        }
          +
          +        var editor = this.editor;
          +        var $textElem = editor.$textElem;
          +        if ($textElem.isContain($containerElem)) {
          +            // 是编辑内容之内的
          +            this._currentRange = range;
          +        }
          +    },
          +
          +    // 折叠选区
          +    collapseRange: function collapseRange(toStart) {
          +        if (toStart == null) {
          +            // 默认为 false
          +            toStart = false;
          +        }
          +        var range = this._currentRange;
          +        if (range) {
          +            range.collapse(toStart);
          +        }
          +    },
          +
          +    // 选中区域的文字
          +    getSelectionText: function getSelectionText() {
          +        var range = this._currentRange;
          +        if (range) {
          +            return this._currentRange.toString();
          +        } else {
          +            return '';
          +        }
          +    },
          +
          +    // 选区的 $Elem
          +    getSelectionContainerElem: function getSelectionContainerElem(range) {
          +        range = range || this._currentRange;
          +        var elem = void 0;
          +        if (range) {
          +            elem = range.commonAncestorContainer;
          +            return $(elem.nodeType === 1 ? elem : elem.parentNode);
          +        }
          +    },
          +    getSelectionStartElem: function getSelectionStartElem(range) {
          +        range = range || this._currentRange;
          +        var elem = void 0;
          +        if (range) {
          +            elem = range.startContainer;
          +            return $(elem.nodeType === 1 ? elem : elem.parentNode);
          +        }
          +    },
          +    getSelectionEndElem: function getSelectionEndElem(range) {
          +        range = range || this._currentRange;
          +        var elem = void 0;
          +        if (range) {
          +            elem = range.endContainer;
          +            return $(elem.nodeType === 1 ? elem : elem.parentNode);
          +        }
          +    },
          +
          +    // 选区是否为空
          +    isSelectionEmpty: function isSelectionEmpty() {
          +        var range = this._currentRange;
          +        if (range && range.startContainer) {
          +            if (range.startContainer === range.endContainer) {
          +                if (range.startOffset === range.endOffset) {
          +                    return true;
          +                }
          +            }
          +        }
          +        return false;
          +    },
          +
          +    // 恢复选区
          +    restoreSelection: function restoreSelection() {
          +        var selection = window.getSelection();
          +        selection.removeAllRanges();
          +        selection.addRange(this._currentRange);
          +    },
          +
          +    // 创建一个空白(即 ​ 字符)选区
          +    createEmptyRange: function createEmptyRange() {
          +        var editor = this.editor;
          +        var range = this.getRange();
          +        var $elem = void 0;
          +
          +        if (!range) {
          +            // 当前无 range
          +            return;
          +        }
          +        if (!this.isSelectionEmpty()) {
          +            // 当前选区必须没有内容才可以
          +            return;
          +        }
          +
          +        try {
          +            // 目前只支持 webkit 内核
          +            if (UA.isWebkit()) {
          +                // 插入 ​
          +                editor.cmd.do('insertHTML', '​');
          +                // 修改 offset 位置
          +                range.setEnd(range.endContainer, range.endOffset + 1);
          +                // 存储
          +                this.saveRange(range);
          +            } else {
          +                $elem = $('');
          +                editor.cmd.do('insertElem', $elem);
          +                this.createRangeByElem($elem, true);
          +            }
          +        } catch (ex) {
          +            // 部分情况下会报错,兼容一下
          +        }
          +    },
          +
          +    // 根据 $Elem 设置选区
          +    createRangeByElem: function createRangeByElem($elem, toStart, isContent) {
          +        // $elem - 经过封装的 elem
          +        // toStart - true 开始位置,false 结束位置
          +        // isContent - 是否选中Elem的内容
          +        if (!$elem.length) {
          +            return;
          +        }
          +
          +        var elem = $elem[0];
          +        var range = document.createRange();
          +
          +        if (isContent) {
          +            range.selectNodeContents(elem);
          +        } else {
          +            range.selectNode(elem);
          +        }
          +
          +        if (typeof toStart === 'boolean') {
          +            range.collapse(toStart);
          +        }
          +
          +        // 存储 range
          +        this.saveRange(range);
          +    }
          +};
          +
          +/*
          +    上传进度条
          +*/
          +
          +function Progress(editor) {
          +    this.editor = editor;
          +    this._time = 0;
          +    this._isShow = false;
          +    this._isRender = false;
          +    this._timeoutId = 0;
          +    this.$textContainer = editor.$textContainerElem;
          +    this.$bar = $('
          '); +} + +Progress.prototype = { + constructor: Progress, + + show: function show(progress) { + var _this = this; + + // 状态处理 + if (this._isShow) { + return; + } + this._isShow = true; + + // 渲染 + var $bar = this.$bar; + if (!this._isRender) { + var $textContainer = this.$textContainer; + $textContainer.append($bar); + } else { + this._isRender = true; + } + + // 改变进度(节流,100ms 渲染一次) + if (Date.now() - this._time > 100) { + if (progress <= 1) { + $bar.css('width', progress * 100 + '%'); + this._time = Date.now(); + } + } + + // 隐藏 + var timeoutId = this._timeoutId; + if (timeoutId) { + clearTimeout(timeoutId); + } + timeoutId = setTimeout(function () { + _this._hide(); + }, 500); + }, + + _hide: function _hide() { + var $bar = this.$bar; + $bar.remove(); + + // 修改状态 + this._time = 0; + this._isShow = false; + this._isRender = false; + } +}; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; +} : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; +}; + +/* + 上传图片 +*/ + +// 构造函数 +function UploadImg(editor) { + this.editor = editor; +} + +// 原型 +UploadImg.prototype = { + constructor: UploadImg, + + // 根据 debug 弹出不同的信息 + _alert: function _alert(alertInfo, debugInfo) { + var editor = this.editor; + var debug = editor.config.debug; + var customAlert = editor.config.customAlert; + + if (debug) { + throw new Error('wangEditor: ' + (debugInfo || alertInfo)); + } else { + if (customAlert && typeof customAlert === 'function') { + customAlert(alertInfo); + } else { + alert(alertInfo); + } + } + }, + + // 根据链接插入图片 + insertLinkImg: function insertLinkImg(link) { + var _this2 = this; + + if (!link) { + return; + } + var editor = this.editor; + var config = editor.config; + + // 校验格式 + var linkImgCheck = config.linkImgCheck; + var checkResult = void 0; + if (linkImgCheck && typeof linkImgCheck === 'function') { + checkResult = linkImgCheck(link); + if (typeof checkResult === 'string') { + // 校验失败,提示信息 + alert(checkResult); + return; + } + } + + editor.cmd.do('insertHTML', ''); + + // 验证图片 url 是否有效,无效的话给出提示 + var img = document.createElement('img'); + img.onload = function () { + var callback = config.linkImgCallback; + if (callback && typeof callback === 'function') { + callback(link); + } + + img = null; + }; + img.onerror = function () { + img = null; + // 无法成功下载图片 + _this2._alert('插入图片错误', 'wangEditor: \u63D2\u5165\u56FE\u7247\u51FA\u9519\uFF0C\u56FE\u7247\u94FE\u63A5\u662F "' + link + '"\uFF0C\u4E0B\u8F7D\u8BE5\u94FE\u63A5\u5931\u8D25'); + return; + }; + img.onabort = function () { + img = null; + }; + img.src = link; + }, + + // 上传图片 + uploadImg: function uploadImg(files) { + var _this3 = this; + + if (!files || !files.length) { + return; + } + + // ------------------------------ 获取配置信息 ------------------------------ + var editor = this.editor; + var config = editor.config; + var uploadImgServer = config.uploadImgServer; + var uploadImgShowBase64 = config.uploadImgShowBase64; + + var maxSize = config.uploadImgMaxSize; + var maxSizeM = maxSize / 1024 / 1024; + var maxLength = config.uploadImgMaxLength || 10000; + var uploadFileName = config.uploadFileName || ''; + var uploadImgParams = config.uploadImgParams || {}; + var uploadImgParamsWithUrl = config.uploadImgParamsWithUrl; + var uploadImgHeaders = config.uploadImgHeaders || {}; + var hooks = config.uploadImgHooks || {}; + var timeout = config.uploadImgTimeout || 3000; + var withCredentials = config.withCredentials; + if (withCredentials == null) { + withCredentials = false; + } + var customUploadImg = config.customUploadImg; + + if (!customUploadImg) { + // 没有 customUploadImg 的情况下,需要如下两个配置才能继续进行图片上传 + if (!uploadImgServer && !uploadImgShowBase64) { + return; + } + } + + // ------------------------------ 验证文件信息 ------------------------------ + var resultFiles = []; + var errInfo = []; + arrForEach(files, function (file) { + var name = file.name; + var size = file.size; + + // chrome 低版本 name === undefined + if (!name || !size) { + return; + } + + if (/\.(jpg|jpeg|png|bmp|gif|webp)$/i.test(name) === false) { + // 后缀名不合法,不是图片 + errInfo.push('\u3010' + name + '\u3011\u4E0D\u662F\u56FE\u7247'); + return; + } + if (maxSize < size) { + // 上传图片过大 + errInfo.push('\u3010' + name + '\u3011\u5927\u4E8E ' + maxSizeM + 'M'); + return; + } + + // 验证通过的加入结果列表 + resultFiles.push(file); + }); + // 抛出验证信息 + if (errInfo.length) { + this._alert('图片验证未通过: \n' + errInfo.join('\n')); + return; + } + if (resultFiles.length > maxLength) { + this._alert('一次最多上传' + maxLength + '张图片'); + return; + } + + // ------------------------------ 自定义上传 ------------------------------ + if (customUploadImg && typeof customUploadImg === 'function') { + customUploadImg(resultFiles, this.insertLinkImg.bind(this)); + + // 阻止以下代码执行 + return; + } + + // 添加图片数据 + var formdata = new FormData(); + arrForEach(resultFiles, function (file) { + var name = uploadFileName || file.name; + formdata.append(name, file); + }); + + // ------------------------------ 上传图片 ------------------------------ + if (uploadImgServer && typeof uploadImgServer === 'string') { + // 添加参数 + var uploadImgServerArr = uploadImgServer.split('#'); + uploadImgServer = uploadImgServerArr[0]; + var uploadImgServerHash = uploadImgServerArr[1] || ''; + objForEach(uploadImgParams, function (key, val) { + // 因使用者反应,自定义参数不能默认 encode ,由 v3.1.1 版本开始注释掉 + // val = encodeURIComponent(val) + + // 第一,将参数拼接到 url 中 + if (uploadImgParamsWithUrl) { + if (uploadImgServer.indexOf('?') > 0) { + uploadImgServer += '&'; + } else { + uploadImgServer += '?'; + } + uploadImgServer = uploadImgServer + key + '=' + val; + } + + // 第二,将参数添加到 formdata 中 + formdata.append(key, val); + }); + if (uploadImgServerHash) { + uploadImgServer += '#' + uploadImgServerHash; + } + + // 定义 xhr + var xhr = new XMLHttpRequest(); + xhr.open('POST', uploadImgServer); + + // 设置超时 + xhr.timeout = timeout; + xhr.ontimeout = function () { + // hook - timeout + if (hooks.timeout && typeof hooks.timeout === 'function') { + hooks.timeout(xhr, editor); + } + + _this3._alert('上传图片超时'); + }; + + // 监控 progress + if (xhr.upload) { + xhr.upload.onprogress = function (e) { + var percent = void 0; + // 进度条 + var progressBar = new Progress(editor); + if (e.lengthComputable) { + percent = e.loaded / e.total; + progressBar.show(percent); + } + }; + } + + // 返回数据 + xhr.onreadystatechange = function () { + var result = void 0; + if (xhr.readyState === 4) { + if (xhr.status < 200 || xhr.status >= 300) { + // hook - error + if (hooks.error && typeof hooks.error === 'function') { + hooks.error(xhr, editor); + } + + // xhr 返回状态错误 + _this3._alert('上传图片发生错误', '\u4E0A\u4F20\u56FE\u7247\u53D1\u751F\u9519\u8BEF\uFF0C\u670D\u52A1\u5668\u8FD4\u56DE\u72B6\u6001\u662F ' + xhr.status); + return; + } + + result = xhr.responseText; + if ((typeof result === 'undefined' ? 'undefined' : _typeof(result)) !== 'object') { + try { + result = JSON.parse(result); + } catch (ex) { + // hook - fail + if (hooks.fail && typeof hooks.fail === 'function') { + hooks.fail(xhr, editor, result); + } + + _this3._alert('上传图片失败', '上传图片返回结果错误,返回结果是: ' + result); + return; + } + } + if (!hooks.customInsert && result.errno != '0') { + // hook - fail + if (hooks.fail && typeof hooks.fail === 'function') { + hooks.fail(xhr, editor, result); + } + + // 数据错误 + _this3._alert('上传图片失败', '上传图片返回结果错误,返回结果 errno=' + result.errno); + } else { + if (hooks.customInsert && typeof hooks.customInsert === 'function') { + // 使用者自定义插入方法 + hooks.customInsert(_this3.insertLinkImg.bind(_this3), result, editor); + } else { + // 将图片插入编辑器 + var data = result.data || []; + data.forEach(function (link) { + _this3.insertLinkImg(link); + }); + } + + // hook - success + if (hooks.success && typeof hooks.success === 'function') { + hooks.success(xhr, editor, result); + } + } + } + }; + + // hook - before + if (hooks.before && typeof hooks.before === 'function') { + var beforeResult = hooks.before(xhr, editor, resultFiles); + if (beforeResult && (typeof beforeResult === 'undefined' ? 'undefined' : _typeof(beforeResult)) === 'object') { + if (beforeResult.prevent) { + // 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传 + this._alert(beforeResult.msg); + return; + } + } + } + + // 自定义 headers + objForEach(uploadImgHeaders, function (key, val) { + xhr.setRequestHeader(key, val); + }); + + // 跨域传 cookie + xhr.withCredentials = withCredentials; + + // 发送请求 + xhr.send(formdata); + + // 注意,要 return 。不去操作接下来的 base64 显示方式 + return; + } + + // ------------------------------ 显示 base64 格式 ------------------------------ + if (uploadImgShowBase64) { + arrForEach(files, function (file) { + var _this = _this3; + var reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = function () { + _this.insertLinkImg(this.result); + }; + }); + } + } +}; + +/* + 编辑器构造函数 +*/ + +// id,累加 +var editorId = 1; + +// 构造函数 +function Editor(toolbarSelector, textSelector) { + if (toolbarSelector == null) { + // 没有传入任何参数,报错 + throw new Error('错误:初始化编辑器时候未传入任何参数,请查阅文档'); + } + // id,用以区分单个页面不同的编辑器对象 + this.id = 'wangEditor-' + editorId++; + + this.toolbarSelector = toolbarSelector; + this.textSelector = textSelector; + + // 自定义配置 + this.customConfig = {}; +} + +// 修改原型 +Editor.prototype = { + constructor: Editor, + + // 初始化配置 + _initConfig: function _initConfig() { + // _config 是默认配置,this.customConfig 是用户自定义配置,将它们 merge 之后再赋值 + var target = {}; + this.config = Object.assign(target, config, this.customConfig); + + // 将语言配置,生成正则表达式 + var langConfig = this.config.lang || {}; + var langArgs = []; + objForEach(langConfig, function (key, val) { + // key 即需要生成正则表达式的规则,如“插入链接” + // val 即需要被替换成的语言,如“insert link” + langArgs.push({ + reg: new RegExp(key, 'img'), + val: val + + }); + }); + this.config.langArgs = langArgs; + }, + + // 初始化 DOM + _initDom: function _initDom() { + var _this = this; + + var toolbarSelector = this.toolbarSelector; + var $toolbarSelector = $(toolbarSelector); + var textSelector = this.textSelector; + + var config$$1 = this.config; + var zIndex = config$$1.zIndex; + + // 定义变量 + var $toolbarElem = void 0, + $textContainerElem = void 0, + $textElem = void 0, + $children = void 0; + + if (textSelector == null) { + // 只传入一个参数,即是容器的选择器或元素,toolbar 和 text 的元素自行创建 + $toolbarElem = $('
          '); + $textContainerElem = $('
          '); + + // 将编辑器区域原有的内容,暂存起来 + $children = $toolbarSelector.children(); + + // 添加到 DOM 结构中 + $toolbarSelector.append($toolbarElem).append($textContainerElem); + + // 自行创建的,需要配置默认的样式 + $toolbarElem.css('background-color', '#f1f1f1').css('border', '1px solid #ccc'); + $textContainerElem.css('border', '1px solid #ccc').css('border-top', 'none').css('height', '300px'); + } else { + // toolbar 和 text 的选择器都有值,记录属性 + $toolbarElem = $toolbarSelector; + $textContainerElem = $(textSelector); + // 将编辑器区域原有的内容,暂存起来 + $children = $textContainerElem.children(); + } + + // 编辑区域 + $textElem = $('
          '); + $textElem.attr('contenteditable', 'true').css('width', '100%').css('height', '100%'); + + // 初始化编辑区域内容 + if ($children && $children.length) { + $textElem.append($children); + } else { + $textElem.append($('


          ')); + } + + // 编辑区域加入DOM + $textContainerElem.append($textElem); + + // 设置通用的 class + $toolbarElem.addClass('w-e-toolbar'); + $textContainerElem.addClass('w-e-text-container'); + $textContainerElem.css('z-index', zIndex); + $textElem.addClass('w-e-text'); + + // 添加 ID + var toolbarElemId = getRandom('toolbar-elem'); + $toolbarElem.attr('id', toolbarElemId); + var textElemId = getRandom('text-elem'); + $textElem.attr('id', textElemId); + + // 记录属性 + this.$toolbarElem = $toolbarElem; + this.$textContainerElem = $textContainerElem; + this.$textElem = $textElem; + this.toolbarElemId = toolbarElemId; + this.textElemId = textElemId; + + // 记录输入法的开始和结束 + var compositionEnd = true; + $textContainerElem.on('compositionstart', function () { + // 输入法开始输入 + compositionEnd = false; + }); + $textContainerElem.on('compositionend', function () { + // 输入法结束输入 + compositionEnd = true; + }); + + // 绑定 onchange + $textContainerElem.on('click keyup', function () { + // 输入法结束才出发 onchange + compositionEnd && _this.change && _this.change(); + }); + $toolbarElem.on('click', function () { + this.change && this.change(); + }); + + //绑定 onfocus 与 onblur 事件 + if (config$$1.onfocus || config$$1.onblur) { + // 当前编辑器是否是焦点状态 + this.isFocus = false; + + $(document).on('click', function (e) { + //判断当前点击元素是否在编辑器内 + var isChild = $textElem.isContain($(e.target)); + + //判断当前点击元素是否为工具栏 + var isToolbar = $toolbarElem.isContain($(e.target)); + var isMenu = $toolbarElem[0] == e.target ? true : false; + + if (!isChild) { + //若为选择工具栏中的功能,则不视为成blur操作 + if (isToolbar && !isMenu) { + return; + } + + if (_this.isFocus) { + _this.onblur && _this.onblur(); + } + _this.isFocus = false; + } else { + if (!_this.isFocus) { + _this.onfocus && _this.onfocus(); + } + _this.isFocus = true; + } + }); + } + }, + + // 封装 command + _initCommand: function _initCommand() { + this.cmd = new Command(this); + }, + + // 封装 selection range API + _initSelectionAPI: function _initSelectionAPI() { + this.selection = new API(this); + }, + + // 添加图片上传 + _initUploadImg: function _initUploadImg() { + this.uploadImg = new UploadImg(this); + }, + + // 初始化菜单 + _initMenus: function _initMenus() { + this.menus = new Menus(this); + this.menus.init(); + }, + + // 添加 text 区域 + _initText: function _initText() { + this.txt = new Text(this); + this.txt.init(); + }, + + // 初始化选区,将光标定位到内容尾部 + initSelection: function initSelection(newLine) { + var $textElem = this.$textElem; + var $children = $textElem.children(); + if (!$children.length) { + // 如果编辑器区域无内容,添加一个空行,重新设置选区 + $textElem.append($('


          ')); + this.initSelection(); + return; + } + + var $last = $children.last(); + + if (newLine) { + // 新增一个空行 + var html = $last.html().toLowerCase(); + var nodeName = $last.getNodeName(); + if (html !== '
          ' && html !== '' || nodeName !== 'P') { + // 最后一个元素不是


          ,添加一个空行,重新设置选区 + $textElem.append($('


          ')); + this.initSelection(); + return; + } + } + + this.selection.createRangeByElem($last, false, true); + this.selection.restoreSelection(); + }, + + // 绑定事件 + _bindEvent: function _bindEvent() { + // -------- 绑定 onchange 事件 -------- + var onChangeTimeoutId = 0; + var beforeChangeHtml = this.txt.html(); + var config$$1 = this.config; + + // onchange 触发延迟时间 + var onchangeTimeout = config$$1.onchangeTimeout; + onchangeTimeout = parseInt(onchangeTimeout, 10); + if (!onchangeTimeout || onchangeTimeout <= 0) { + onchangeTimeout = 200; + } + + var onchange = config$$1.onchange; + if (onchange && typeof onchange === 'function') { + // 触发 change 的有三个场景: + // 1. $textContainerElem.on('click keyup') + // 2. $toolbarElem.on('click') + // 3. editor.cmd.do() + this.change = function () { + // 判断是否有变化 + var currentHtml = this.txt.html(); + + if (currentHtml.length === beforeChangeHtml.length) { + // 需要比较每一个字符 + if (currentHtml === beforeChangeHtml) { + return; + } + } + + // 执行,使用节流 + if (onChangeTimeoutId) { + clearTimeout(onChangeTimeoutId); + } + onChangeTimeoutId = setTimeout(function () { + // 触发配置的 onchange 函数 + onchange(currentHtml); + beforeChangeHtml = currentHtml; + }, onchangeTimeout); + }; + } + + // -------- 绑定 onblur 事件 -------- + var onblur = config$$1.onblur; + if (onblur && typeof onblur === 'function') { + this.onblur = function () { + var currentHtml = this.txt.html(); + onblur(currentHtml); + }; + } + + // -------- 绑定 onfocus 事件 -------- + var onfocus = config$$1.onfocus; + if (onfocus && typeof onfocus === 'function') { + this.onfocus = function () { + onfocus(); + }; + } + }, + + // 创建编辑器 + create: function create() { + // 初始化配置信息 + this._initConfig(); + + // 初始化 DOM + this._initDom(); + + // 封装 command API + this._initCommand(); + + // 封装 selection range API + this._initSelectionAPI(); + + // 添加 text + this._initText(); + + // 初始化菜单 + this._initMenus(); + + // 添加 图片上传 + this._initUploadImg(); + + // 初始化选区,将光标定位到内容尾部 + this.initSelection(true); + + // 绑定事件 + this._bindEvent(); + }, + + // 解绑所有事件(暂时不对外开放) + _offAllEvent: function _offAllEvent() { + $.offAll(); + } +}; + +// 检验是否浏览器环境 +try { + document; +} catch (ex) { + throw new Error('请在浏览器环境下运行'); +} + +// polyfill +polyfill(); + +// 这里的 `inlinecss` 将被替换成 css 代码的内容,详情可去 ./gulpfile.js 中搜索 `inlinecss` 关键字 +var inlinecss = '.w-e-toolbar,.w-e-text-container,.w-e-menu-panel { padding: 0; margin: 0; box-sizing: border-box;}.w-e-toolbar *,.w-e-text-container *,.w-e-menu-panel * { padding: 0; margin: 0; box-sizing: border-box;}.w-e-clear-fix:after { content: ""; display: table; clear: both;}.w-e-toolbar .w-e-droplist { position: absolute; left: 0; top: 0; background-color: #fff; border: 1px solid #f1f1f1; border-right-color: #ccc; border-bottom-color: #ccc;}.w-e-toolbar .w-e-droplist .w-e-dp-title { text-align: center; color: #999; line-height: 2; border-bottom: 1px solid #f1f1f1; font-size: 13px;}.w-e-toolbar .w-e-droplist ul.w-e-list { list-style: none; line-height: 1;}.w-e-toolbar .w-e-droplist ul.w-e-list li.w-e-item { color: #333; padding: 5px 0;}.w-e-toolbar .w-e-droplist ul.w-e-list li.w-e-item:hover { background-color: #f1f1f1;}.w-e-toolbar .w-e-droplist ul.w-e-block { list-style: none; text-align: left; padding: 5px;}.w-e-toolbar .w-e-droplist ul.w-e-block li.w-e-item { display: inline-block; *display: inline; *zoom: 1; padding: 3px 5px;}.w-e-toolbar .w-e-droplist ul.w-e-block li.w-e-item:hover { background-color: #f1f1f1;}@font-face { font-family: \'w-e-icon\'; src: url(data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAABhQAAsAAAAAGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABCAAAAGAAAABgDxIPBGNtYXAAAAFoAAABBAAAAQQrSf4BZ2FzcAAAAmwAAAAIAAAACAAAABBnbHlmAAACdAAAEvAAABLwfpUWUWhlYWQAABVkAAAANgAAADYQp00kaGhlYQAAFZwAAAAkAAAAJAfEA+FobXR4AAAVwAAAAIQAAACEeAcD7GxvY2EAABZEAAAARAAAAERBSEX+bWF4cAAAFogAAAAgAAAAIAAsALZuYW1lAAAWqAAAAYYAAAGGmUoJ+3Bvc3QAABgwAAAAIAAAACAAAwAAAAMD3gGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAA8fwDwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEAOgAAAA2ACAABAAWAAEAIOkG6Q3pEulH6Wbpd+m56bvpxunL6d/qDepc6l/qZepo6nHqefAN8BTxIPHc8fz//f//AAAAAAAg6QbpDekS6UfpZel36bnpu+nG6cvp3+oN6lzqX+pi6mjqcep38A3wFPEg8dzx/P/9//8AAf/jFv4W+Bb0FsAWoxaTFlIWURZHFkMWMBYDFbUVsxWxFa8VpxWiEA8QCQ7+DkMOJAADAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAACAAD/wAQAA8AABAATAAABNwEnAQMuAScTNwEjAQMlATUBBwGAgAHAQP5Anxc7MmOAAYDA/oDAAoABgP6ATgFAQAHAQP5A/p0yOxcBEU4BgP6A/YDAAYDA/oCAAAQAAAAABAADgAAQACEALQA0AAABOAExETgBMSE4ATEROAExITUhIgYVERQWMyEyNjURNCYjBxQGIyImNTQ2MzIWEyE1EwEzNwPA/IADgPyAGiYmGgOAGiYmGoA4KCg4OCgoOED9AOABAEDgA0D9AAMAQCYa/QAaJiYaAwAaJuAoODgoKDg4/biAAYD+wMAAAAIAAABABAADQAA4ADwAAAEmJy4BJyYjIgcOAQcGBwYHDgEHBhUUFx4BFxYXFhceARcWMzI3PgE3Njc2Nz4BNzY1NCcuAScmJwERDQED1TY4OXY8PT8/PTx2OTg2CwcICwMDAwMLCAcLNjg5djw9Pz89PHY5ODYLBwgLAwMDAwsIBwv9qwFA/sADIAgGBggCAgICCAYGCCkqKlktLi8vLi1ZKiopCAYGCAICAgIIBgYIKSoqWS0uLy8uLVkqKin94AGAwMAAAAAAAgDA/8ADQAPAABsAJwAAASIHDgEHBhUUFx4BFxYxMDc+ATc2NTQnLgEnJgMiJjU0NjMyFhUUBgIAQjs6VxkZMjJ4MjIyMngyMhkZVzo7QlBwcFBQcHADwBkZVzo7Qnh9fcxBQUFBzH19eEI7OlcZGf4AcFBQcHBQUHAAAAEAAAAABAADgAArAAABIgcOAQcGBycRISc+ATMyFx4BFxYVFAcOAQcGBxc2Nz4BNzY1NCcuAScmIwIANTIyXCkpI5YBgJA1i1BQRUZpHh4JCSIYGB5VKCAgLQwMKCiLXl1qA4AKCycbHCOW/oCQNDweHmlGRVArKClJICEaYCMrK2I2NjlqXV6LKCgAAQAAAAAEAAOAACoAABMUFx4BFxYXNyYnLgEnJjU0Nz4BNzYzMhYXByERByYnLgEnJiMiBw4BBwYADAwtICAoVR4YGCIJCR4eaUZFUFCLNZABgJYjKSlcMjI1al1eiygoAYA5NjZiKysjYBohIEkpKCtQRUZpHh48NJABgJYjHBsnCwooKIteXQAAAAACAAAAQAQBAwAAJgBNAAATMhceARcWFRQHDgEHBiMiJy4BJyY1JzQ3PgE3NjMVIgYHDgEHPgEhMhceARcWFRQHDgEHBiMiJy4BJyY1JzQ3PgE3NjMVIgYHDgEHPgHhLikpPRESEhE9KSkuLikpPRESASMjelJRXUB1LQkQBwgSAkkuKSk9ERISET0pKS4uKSk9ERIBIyN6UlFdQHUtCRAHCBICABIRPSkpLi4pKT0REhIRPSkpLiBdUVJ6IyOAMC4IEwoCARIRPSkpLi4pKT0REhIRPSkpLiBdUVJ6IyOAMC4IEwoCAQAABgBA/8AEAAPAAAMABwALABEAHQApAAAlIRUhESEVIREhFSEnESM1IzUTFTMVIzU3NSM1MxUVESM1MzUjNTM1IzUBgAKA/YACgP2AAoD9gMBAQECAwICAwMCAgICAgIACAIACAIDA/wDAQP3yMkCSPDJAku7+wEBAQEBAAAYAAP/ABAADwAADAAcACwAXACMALwAAASEVIREhFSERIRUhATQ2MzIWFRQGIyImETQ2MzIWFRQGIyImETQ2MzIWFRQGIyImAYACgP2AAoD9gAKA/YD+gEs1NUtLNTVLSzU1S0s1NUtLNTVLSzU1SwOAgP8AgP8AgANANUtLNTVLS/61NUtLNTVLS/61NUtLNTVLSwADAAAAAAQAA6AAAwANABQAADchFSElFSE1EyEVITUhJQkBIxEjEQAEAPwABAD8AIABAAEAAQD9YAEgASDggEBAwEBAAQCAgMABIP7g/wABAAAAAAACAB7/zAPiA7QAMwBkAAABIiYnJicmNDc2PwE+ATMyFhcWFxYUBwYPAQYiJyY0PwE2NCcuASMiBg8BBhQXFhQHDgEjAyImJyYnJjQ3Nj8BNjIXFhQPAQYUFx4BMzI2PwE2NCcmNDc2MhcWFxYUBwYPAQ4BIwG4ChMIIxISEhIjwCNZMTFZIyMSEhISI1gPLA8PD1gpKRQzHBwzFMApKQ8PCBMKuDFZIyMSEhISI1gPLA8PD1gpKRQzHBwzFMApKQ8PDysQIxISEhIjwCNZMQFECAckLS1eLS0kwCIlJSIkLS1eLS0kVxAQDysPWCl0KRQVFRTAKXQpDysQBwj+iCUiJC0tXi0tJFcQEA8rD1gpdCkUFRUUwCl0KQ8rEA8PJC0tXi0tJMAiJQAAAAAFAAD/wAQAA8AAGwA3AFMAXwBrAAAFMjc+ATc2NTQnLgEnJiMiBw4BBwYVFBceARcWEzIXHgEXFhUUBw4BBwYjIicuAScmNTQ3PgE3NhMyNz4BNzY3BgcOAQcGIyInLgEnJicWFx4BFxYnNDYzMhYVFAYjIiYlNDYzMhYVFAYjIiYCAGpdXosoKCgoi15dampdXosoKCgoi15dalZMTHEgISEgcUxMVlZMTHEgISEgcUxMVisrKlEmJiMFHBtWODc/Pzc4VhscBSMmJlEqK9UlGxslJRsbJQGAJRsbJSUbGyVAKCiLXl1qal1eiygoKCiLXl1qal1eiygoA6AhIHFMTFZWTExxICEhIHFMTFZWTExxICH+CQYGFRAQFEM6OlYYGRkYVjo6QxQQEBUGBvcoODgoKDg4KCg4OCgoODgAAAMAAP/ABAADwAAbADcAQwAAASIHDgEHBhUUFx4BFxYzMjc+ATc2NTQnLgEnJgMiJy4BJyY1NDc+ATc2MzIXHgEXFhUUBw4BBwYTBycHFwcXNxc3JzcCAGpdXosoKCgoi15dampdXosoKCgoi15dalZMTHEgISEgcUxMVlZMTHEgISEgcUxMSqCgYKCgYKCgYKCgA8AoKIteXWpqXV6LKCgoKIteXWpqXV6LKCj8YCEgcUxMVlZMTHEgISEgcUxMVlZMTHEgIQKgoKBgoKBgoKBgoKAAAQBl/8ADmwPAACkAAAEiJiMiBw4BBwYVFBYzLgE1NDY3MAcGAgcGBxUhEzM3IzceATMyNjcOAQMgRGhGcVNUbRobSUgGDWVKEBBLPDxZAT1sxizXNC1VJi5QGB09A7AQHh1hPj9BTTsLJjeZbwN9fv7Fj5AjGQIAgPYJDzdrCQcAAAAAAgAAAAAEAAOAAAkAFwAAJTMHJzMRIzcXIyURJyMRMxUhNTMRIwcRA4CAoKCAgKCggP8AQMCA/oCAwEDAwMACAMDAwP8AgP1AQEACwIABAAADAMAAAANAA4AAFgAfACgAAAE+ATU0Jy4BJyYjIREhMjc+ATc2NTQmATMyFhUUBisBEyMRMzIWFRQGAsQcIBQURi4vNf7AAYA1Ly5GFBRE/oRlKjw8KWafn58sPj4B2yJULzUvLkYUFPyAFBRGLi81RnQBRks1NUv+gAEASzU1SwAAAAACAMAAAANAA4AAHwAjAAABMxEUBw4BBwYjIicuAScmNREzERQWFx4BMzI2Nz4BNQEhFSECwIAZGVc6O0JCOzpXGRmAGxgcSSgoSRwYG/4AAoD9gAOA/mA8NDVOFhcXFk41NDwBoP5gHjgXGBsbGBc4Hv6ggAAAAAABAIAAAAOAA4AACwAAARUjATMVITUzASM1A4CA/sCA/kCAAUCAA4BA/QBAQAMAQAABAAAAAAQAA4AAPQAAARUjHgEVFAYHDgEjIiYnLgE1MxQWMzI2NTQmIyE1IS4BJy4BNTQ2Nz4BMzIWFx4BFSM0JiMiBhUUFjMyFhcEAOsVFjUwLHE+PnEsMDWAck5OcnJO/gABLAIEATA1NTAscT4+cSwwNYByTk5yck47bisBwEAdQSI1YiQhJCQhJGI1NExMNDRMQAEDASRiNTViJCEkJCEkYjU0TEw0NEwhHwAAAAcAAP/ABAADwAADAAcACwAPABMAGwAjAAATMxUjNzMVIyUzFSM3MxUjJTMVIwMTIRMzEyETAQMhAyMDIQMAgIDAwMABAICAwMDAAQCAgBAQ/QAQIBACgBD9QBADABAgEP2AEAHAQEBAQEBAQEBAAkD+QAHA/oABgPwAAYD+gAFA/sAAAAoAAAAABAADgAADAAcACwAPABMAFwAbAB8AIwAnAAATESERATUhFR0BITUBFSE1IxUhNREhFSElIRUhETUhFQEhFSEhNSEVAAQA/YABAP8AAQD/AED/AAEA/wACgAEA/wABAPyAAQD/AAKAAQADgPyAA4D9wMDAQMDAAgDAwMDA/wDAwMABAMDA/sDAwMAAAAUAAAAABAADgAADAAcACwAPABMAABMhFSEVIRUhESEVIREhFSERIRUhAAQA/AACgP2AAoD9gAQA/AAEAPwAA4CAQID/AIABQID/AIAAAAAABQAAAAAEAAOAAAMABwALAA8AEwAAEyEVIRchFSERIRUhAyEVIREhFSEABAD8AMACgP2AAoD9gMAEAPwABAD8AAOAgECA/wCAAUCA/wCAAAAFAAAAAAQAA4AAAwAHAAsADwATAAATIRUhBSEVIREhFSEBIRUhESEVIQAEAPwAAYACgP2AAoD9gP6ABAD8AAQA/AADgIBAgP8AgAFAgP8AgAAAAAABAD8APwLmAuYALAAAJRQPAQYjIi8BBwYjIi8BJjU0PwEnJjU0PwE2MzIfATc2MzIfARYVFA8BFxYVAuYQThAXFxCoqBAXFhBOEBCoqBAQThAWFxCoqBAXFxBOEBCoqBDDFhBOEBCoqBAQThAWFxCoqBAXFxBOEBCoqBAQThAXFxCoqBAXAAAABgAAAAADJQNuABQAKAA8AE0AVQCCAAABERQHBisBIicmNRE0NzY7ATIXFhUzERQHBisBIicmNRE0NzY7ATIXFhcRFAcGKwEiJyY1ETQ3NjsBMhcWExEhERQXFhcWMyEyNzY3NjUBIScmJyMGBwUVFAcGKwERFAcGIyEiJyY1ESMiJyY9ATQ3NjsBNzY3NjsBMhcWHwEzMhcWFQElBgUIJAgFBgYFCCQIBQaSBQUIJQgFBQUFCCUIBQWSBQUIJQgFBQUFCCUIBQVJ/gAEBAUEAgHbAgQEBAT+gAEAGwQGtQYEAfcGBQg3Ghsm/iUmGxs3CAUFBQUIsSgIFxYXtxcWFgkosAgFBgIS/rcIBQUFBQgBSQgFBgYFCP63CAUFBQUIAUkIBQYGBQj+twgFBQUFCAFJCAUGBgX+WwId/eMNCwoFBQUFCgsNAmZDBQICBVUkCAYF/eMwIiMhIi8CIAUGCCQIBQVgFQ8PDw8VYAUFCAACAAcASQO3Aq8AGgAuAAAJAQYjIi8BJjU0PwEnJjU0PwE2MzIXARYVFAcBFRQHBiMhIicmPQE0NzYzITIXFgFO/vYGBwgFHQYG4eEGBh0FCAcGAQoGBgJpBQUI/dsIBQUFBQgCJQgFBQGF/vYGBhwGCAcG4OEGBwcGHQUF/vUFCAcG/vslCAUFBQUIJQgFBQUFAAAAAQAjAAAD3QNuALMAACUiJyYjIgcGIyInJjU0NzY3Njc2NzY9ATQnJiMhIgcGHQEUFxYXFjMWFxYVFAcGIyInJiMiBwYjIicmNTQ3Njc2NzY3Nj0BETQ1NDU0JzQnJicmJyYnJicmIyInJjU0NzYzMhcWMzI3NjMyFxYVFAcGIwYHBgcGHQEUFxYzITI3Nj0BNCcmJyYnJjU0NzYzMhcWMzI3NjMyFxYVFAcGByIHBgcGFREUFxYXFhcyFxYVFAcGIwPBGTMyGhkyMxkNCAcJCg0MERAKEgEHFf5+FgcBFQkSEw4ODAsHBw4bNTUaGDExGA0HBwkJCwwQDwkSAQIBAgMEBAUIEhENDQoLBwcOGjU1GhgwMRgOBwcJCgwNEBAIFAEHDwGQDgcBFAoXFw8OBwcOGTMyGRkxMRkOBwcKCg0NEBEIFBQJEREODQoLBwcOAAICAgIMCw8RCQkBAQMDBQxE4AwFAwMFDNRRDQYBAgEICBIPDA0CAgICDAwOEQgJAQIDAwUNRSEB0AINDQgIDg4KCgsLBwcDBgEBCAgSDwwNAgICAg0MDxEICAECAQYMULYMBwEBBwy2UAwGAQEGBxYPDA0CAgICDQwPEQgIAQECBg1P/eZEDAYCAgEJCBEPDA0AAAIAAP+3A/8DtwATADkAAAEyFxYVFAcCBwYjIicmNTQ3ATYzARYXFh8BFgcGIyInJicmJyY1FhcWFxYXFjMyNzY3Njc2NzY3NjcDmygeHhq+TDdFSDQ0NQFtISn9+BcmJy8BAkxMe0c2NiEhEBEEExQQEBIRCRcIDxITFRUdHR4eKQO3GxooJDP+mUY0NTRJSTABSx/9sSsfHw0oek1MGhsuLzo6RAMPDgsLCgoWJRsaEREKCwQEAgABAAAAAAAA9evv618PPPUACwQAAAAAANbEBFgAAAAA1sQEWAAA/7cEAQPAAAAACAACAAAAAAAAAAEAAAPA/8AAAAQAAAD//wQBAAEAAAAAAAAAAAAAAAAAAAAhBAAAAAAAAAAAAAAAAgAAAAQAAAAEAAAABAAAAAQAAMAEAAAABAAAAAQAAAAEAABABAAAAAQAAAAEAAAeBAAAAAQAAAAEAABlBAAAAAQAAMAEAADABAAAgAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAMlAD8DJQAAA74ABwQAACMD/wAAAAAAAAAKABQAHgBMAJQA+AE2AXwBwgI2AnQCvgLoA34EHgSIBMoE8gU0BXAFiAXgBiIGagaSBroG5AcoB+AIKgkcCXgAAQAAACEAtAAKAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAAcAAAABAAAAAAACAAcAYAABAAAAAAADAAcANgABAAAAAAAEAAcAdQABAAAAAAAFAAsAFQABAAAAAAAGAAcASwABAAAAAAAKABoAigADAAEECQABAA4ABwADAAEECQACAA4AZwADAAEECQADAA4APQADAAEECQAEAA4AfAADAAEECQAFABYAIAADAAEECQAGAA4AUgADAAEECQAKADQApGljb21vb24AaQBjAG8AbQBvAG8AblZlcnNpb24gMS4wAFYAZQByAHMAaQBvAG4AIAAxAC4AMGljb21vb24AaQBjAG8AbQBvAG8Abmljb21vb24AaQBjAG8AbQBvAG8AblJlZ3VsYXIAUgBlAGcAdQBsAGEAcmljb21vb24AaQBjAG8AbQBvAG8AbkZvbnQgZ2VuZXJhdGVkIGJ5IEljb01vb24uAEYAbwBuAHQAIABnAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4ALgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=) format(\'truetype\'); font-weight: normal; font-style: normal;}[class^="w-e-icon-"],[class*=" w-e-icon-"] { /* use !important to prevent issues with browser extensions that change fonts */ font-family: \'w-e-icon\' !important; speak: none; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; line-height: 1; /* Better Font Rendering =========== */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;}.w-e-icon-close:before { content: "\\f00d";}.w-e-icon-upload2:before { content: "\\e9c6";}.w-e-icon-trash-o:before { content: "\\f014";}.w-e-icon-header:before { content: "\\f1dc";}.w-e-icon-pencil2:before { content: "\\e906";}.w-e-icon-paint-brush:before { content: "\\f1fc";}.w-e-icon-image:before { content: "\\e90d";}.w-e-icon-play:before { content: "\\e912";}.w-e-icon-location:before { content: "\\e947";}.w-e-icon-undo:before { content: "\\e965";}.w-e-icon-redo:before { content: "\\e966";}.w-e-icon-quotes-left:before { content: "\\e977";}.w-e-icon-list-numbered:before { content: "\\e9b9";}.w-e-icon-list2:before { content: "\\e9bb";}.w-e-icon-link:before { content: "\\e9cb";}.w-e-icon-happy:before { content: "\\e9df";}.w-e-icon-bold:before { content: "\\ea62";}.w-e-icon-underline:before { content: "\\ea63";}.w-e-icon-italic:before { content: "\\ea64";}.w-e-icon-strikethrough:before { content: "\\ea65";}.w-e-icon-table2:before { content: "\\ea71";}.w-e-icon-paragraph-left:before { content: "\\ea77";}.w-e-icon-paragraph-center:before { content: "\\ea78";}.w-e-icon-paragraph-right:before { content: "\\ea79";}.w-e-icon-terminal:before { content: "\\f120";}.w-e-icon-page-break:before { content: "\\ea68";}.w-e-icon-cancel-circle:before { content: "\\ea0d";}.w-e-icon-font:before { content: "\\ea5c";}.w-e-icon-text-heigh:before { content: "\\ea5f";}.w-e-toolbar { display: -webkit-box; display: -ms-flexbox; display: flex; padding: 0 5px; /* flex-wrap: wrap; */ /* 单个菜单 */}.w-e-toolbar .w-e-menu { position: relative; text-align: center; padding: 5px 10px; cursor: pointer;}.w-e-toolbar .w-e-menu i { color: #999;}.w-e-toolbar .w-e-menu:hover i { color: #333;}.w-e-toolbar .w-e-active i { color: #1e88e5;}.w-e-toolbar .w-e-active:hover i { color: #1e88e5;}.w-e-text-container .w-e-panel-container { position: absolute; top: 0; left: 50%; border: 1px solid #ccc; border-top: 0; box-shadow: 1px 1px 2px #ccc; color: #333; background-color: #fff; /* 为 emotion panel 定制的样式 */ /* 上传图片的 panel 定制样式 */}.w-e-text-container .w-e-panel-container .w-e-panel-close { position: absolute; right: 0; top: 0; padding: 5px; margin: 2px 5px 0 0; cursor: pointer; color: #999;}.w-e-text-container .w-e-panel-container .w-e-panel-close:hover { color: #333;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-title { list-style: none; display: -webkit-box; display: -ms-flexbox; display: flex; font-size: 14px; margin: 2px 10px 0 10px; border-bottom: 1px solid #f1f1f1;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-title .w-e-item { padding: 3px 5px; color: #999; cursor: pointer; margin: 0 3px; position: relative; top: 1px;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-title .w-e-active { color: #333; border-bottom: 1px solid #333; cursor: default; font-weight: 700;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content { padding: 10px 15px 10px 15px; font-size: 16px; /* 输入框的样式 */ /* 按钮的样式 */}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input:focus,.w-e-text-container .w-e-panel-container .w-e-panel-tab-content textarea:focus,.w-e-text-container .w-e-panel-container .w-e-panel-tab-content button:focus { outline: none;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content textarea { width: 100%; border: 1px solid #ccc; padding: 5px;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content textarea:focus { border-color: #1e88e5;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text] { border: none; border-bottom: 1px solid #ccc; font-size: 14px; height: 20px; color: #333; text-align: left;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text].small { width: 30px; text-align: center;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text].block { display: block; width: 100%; margin: 10px 0;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text]:focus { border-bottom: 2px solid #1e88e5;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button { font-size: 14px; color: #1e88e5; border: none; padding: 5px 10px; background-color: #fff; cursor: pointer; border-radius: 3px;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.left { float: left; margin-right: 10px;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.right { float: right; margin-left: 10px;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.gray { color: #999;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.red { color: #c24f4a;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button:hover { background-color: #f1f1f1;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container:after { content: ""; display: table; clear: both;}.w-e-text-container .w-e-panel-container .w-e-emoticon-container .w-e-item { cursor: pointer; font-size: 18px; padding: 0 3px; display: inline-block; *display: inline; *zoom: 1;}.w-e-text-container .w-e-panel-container .w-e-up-img-container { text-align: center;}.w-e-text-container .w-e-panel-container .w-e-up-img-container .w-e-up-btn { display: inline-block; *display: inline; *zoom: 1; color: #999; cursor: pointer; font-size: 60px; line-height: 1;}.w-e-text-container .w-e-panel-container .w-e-up-img-container .w-e-up-btn:hover { color: #333;}.w-e-text-container { position: relative;}.w-e-text-container .w-e-progress { position: absolute; background-color: #1e88e5; bottom: 0; left: 0; height: 1px;}.w-e-text { padding: 0 10px; overflow-y: scroll;}.w-e-text p,.w-e-text h1,.w-e-text h2,.w-e-text h3,.w-e-text h4,.w-e-text h5,.w-e-text table,.w-e-text pre { margin: 10px 0; line-height: 1.5;}.w-e-text ul,.w-e-text ol { margin: 10px 0 10px 20px;}.w-e-text blockquote { display: block; border-left: 8px solid #d0e5f2; padding: 5px 10px; margin: 10px 0; line-height: 1.4; font-size: 100%; background-color: #f1f1f1;}.w-e-text code { display: inline-block; *display: inline; *zoom: 1; background-color: #f1f1f1; border-radius: 3px; padding: 3px 5px; margin: 0 3px;}.w-e-text pre code { display: block;}.w-e-text table { border-top: 1px solid #ccc; border-left: 1px solid #ccc;}.w-e-text table td,.w-e-text table th { border-bottom: 1px solid #ccc; border-right: 1px solid #ccc; padding: 3px 5px;}.w-e-text table th { border-bottom: 2px solid #ccc; text-align: center;}.w-e-text:focus { outline: none;}.w-e-text img { cursor: pointer;}.w-e-text img:hover { box-shadow: 0 0 5px #333;}'; + +// 将 css 代码添加到 "].join(""),a=f(o.layHeader.html());a.append(o.layMain.find("table").html()),a.append(o.layTotal.find("table").html()),a.find("th.layui-table-patch").remove(),a.find("thead>tr>th."+F).filter(function(e,t){return!f(t).children("."+u).length}).remove(),a.find("tbody>tr>td."+F).remove(),t.document.write(e+a.prop("outerHTML")),t.document.close(),layui.device("edg").edg?(t.onafterprint=t.close,t.print()):(t.print(),t.close())}}});"object"==typeof e.defaultToolbar&&(l=[],e.defaultToolbar=f.map(e.defaultToolbar,function(e,t){var a="string"==typeof e,i=a?n[e]:e;return i&&(!(i=i.name&&n[i.name]?f.extend({},n[i.name],i):i).name&&a&&(i.name=e),l.push('
          ')),i}),o.layTool.find(".layui-table-tool-self").html(l.join("")))},n.prototype.renderPagebar=function(){var e,t=this.config,a=this.layPagebar=f('
          ');t.pagebar&&((e=f(t.pagebar).html()||"")&&a.append(m(e).render(t)),this.layPage.append(a))},n.prototype.setParentCol=function(e,t){var a=this.config,i=this.layHeader.find('th[data-key="'+t+'"]'),l=parseInt(i.attr("colspan"))||0;i[0]&&(t=t.split("-"),t=a.cols[t[1]][t[2]],e?l--:l++,i.attr("colspan",l),i[l?"removeClass":"addClass"](W),t.colspan2=l,t.hide=l<1,a=i.data("parentkey"))&&this.setParentCol(e,a)},n.prototype.setColsPatch=function(){var a=this,e=a.config;layui.each(e.cols,function(e,t){layui.each(t,function(e,t){t.hide&&a.setParentCol(t.hide,t.parentKey)})})},n.prototype.setGroupWidth=function(i){var e,l=this;l.config.cols.length<=1||((e=l.layHeader.find((i?"th[data-key="+i.data("parentkey")+"]>":"")+"."+u)).css("width",0),layui.each(e.get().reverse(),function(){var e=f(this),t=e.parent().data("key"),a=0;l.layHeader.eq(0).find("th[data-parentkey="+t+"]").width(function(e,t){f(this).hasClass(W)||0o.layMain.prop("clientHeight")&&(e.style.width=parseFloat(e.style.width)-i+"px")}),!p&&h?y.width(o.getContentWidth(l)):y.width("auto"),o.setGroupWidth()},n.prototype.resize=function(){var e=this;e.layMain&&("isConnected"in e.layMain[0]?e.layMain[0].isConnected:f.contains(document.body,e.layMain[0]))&&(e.fullSize(),e.setColsWidth(),e.scrollPatch())},n.prototype.reload=function(e,t,a){var i=this;e=e||{},delete i.haveInit,layui.each(e,function(e,t){"array"===layui.type(t)&&delete i.config[e]}),i.config=f.extend(t,{},i.config,e),"reloadData"!==a&&(layui.each(i.config.cols,function(e,t){layui.each(t,function(e,t){delete t.colspan2})}),delete i.config.HAS_SET_COLS_PATCH),i.render(a)},n.prototype.errorView=function(e){var t=this,a=t.layMain.find("."+h),e=f('
          '+(e||"Error")+"
          ");a[0]&&(t.layNone.remove(),a.remove()),t.layFixed.addClass(W),t.layMain.find("tbody").html(""),t.layMain.append(t.layNone=e),t.layTotal.addClass(y),t.layPage.find(P).addClass(y),k.cache[t.key]=[],t.syncCheckAll(),t.renderForm(),t.setColsWidth(),t.loading(!1)},n.prototype.page=1,n.prototype.pullData=function(i,l){var e,t,n=this,o=n.config,a=(o.HAS_SET_COLS_PATCH||n.setColsPatch(),o.HAS_SET_COLS_PATCH=!0,o.request),d=o.response,r=function(){"object"==typeof o.initSort&&n.sort({field:o.initSort.field,type:o.initSort.type,reloadType:l.type})},c=function(e,t){n.setColsWidth(),n.loading(!1),"function"==typeof o.done&&o.done(e,i,e[d.countName],t)};l=l||{},"function"==typeof o.before&&o.before(o),n.startTime=(new Date).getTime(),l.renderData?((e={})[d.dataName]=k.cache[n.key],e[d.countName]=o.url?"object"===layui.type(o.page)?o.page.count:e[d.dataName].length:o.data.length,"object"==typeof o.totalRow&&(e[d.totalRowName]=f.extend({},n.totalRow)),n.renderData({res:e,curr:i,count:e[d.countName],type:l.type,sort:!0}),c(e,"renderData")):o.url?(t={},o.page&&(t[a.pageName]=i,t[a.limitName]=o.limit),a=f.extend(t,o.where),o.contentType&&0==o.contentType.indexOf("application/json")&&(a=JSON.stringify(a)),n.loading(!0),n._xhr&&4!==n._xhr.readyState&&(n._xhrAbort=!0,n._xhr.abort()),n._xhr=f.ajax({type:o.method||"get",url:o.url,contentType:o.contentType,data:a,dataType:o.dataType||"json",jsonpCallback:o.jsonpCallback,headers:o.headers||{},complete:"function"==typeof o.complete?o.complete:undefined,success:function(e){var t,a;(e="function"==typeof o.parseData?o.parseData(e)||e:e)[d.statusName]!=d.statusCode?n.errorView(e[d.msgName]||'\u8fd4\u56de\u7684\u6570\u636e\u4e0d\u7b26\u5408\u89c4\u8303\uff0c\u6b63\u786e\u7684\u6210\u529f\u72b6\u6001\u7801\u5e94\u4e3a\uff1a"'+d.statusName+'": '+d.statusCode):(t=e[d.countName],(a=Math.ceil(t/o.limit)||1)','
          "+function(){var e,t=f.extend(!0,{LAY_COL:l},o),a=k.config.checkName,i=k.config.disabledName;switch(l.type){case"checkbox":return'';case"radio":return'';case"numbers":return c}return l.toolbar?m(f(l.toolbar).html()||"").render(t):T.call(s,{item3:l,content:n,tplData:t})}(),"
          "].join(""),i.push(e),l.fixed&&"right"!==l.fixed&&d.push(e),"right"===l.fixed&&r.push(e))}),e=['data-index="'+e+'"'],o[k.config.checkName]&&e.push('class="'+A+'"'),e=e.join(" "),y.push(""+i.join("")+""),h.push(""+d.join("")+""),p.push(""+r.join("")+""))}),{trs:y,trs_fixed:h,trs_fixed_r:p}},k.getTrHtml=function(e,t){e=C(e);return e.getTrHtml(t,null,e.page)},n.prototype.renderData=function(e){var a=this,i=a.config,t=e.res,l=e.curr,n=a.count=e.count,o=e.sort,d=t[i.response.dataName]||[],t=t[i.response.totalRowName],r=[],c=[],s=[],u=function(){if(!o&&a.sortKey)return a.sort({field:a.sortKey.field,type:a.sortKey.sort,pull:!0,reloadType:e.type});a.getTrHtml(d,o,l,{trs:r,trs_fixed:c,trs_fixed_r:s}),"fixed"===i.scrollPos&&"reloadData"===e.type||a.layBody.scrollTop(0),"reset"===i.scrollPos&&a.layBody.scrollLeft(0),a.layMain.find("."+h).remove(),a.layMain.find("tbody").html(r.join("")),a.layFixLeft.find("tbody").html(c.join("")),a.layFixRight.find("tbody").html(s.join("")),a.syncCheckAll(),a.renderForm(),a.fullSize(),a.haveInit?a.scrollPatch():setTimeout(function(){a.scrollPatch()},50),a.haveInit=!0,g.close(a.tipsIndex)};return k.cache[a.key]=d,a.layTotal[0==d.length?"addClass":"removeClass"](y),a.layPage[i.page||i.pagebar?"removeClass":"addClass"](W),a.layPage.find(P)[!i.page||0==n||0===d.length&&1==l?"addClass":"removeClass"](y),0===d.length?a.errorView(i.text.none):(a.layFixLeft.removeClass(W),o?u():(u(),a.renderTotal(d,t),a.layTotal&&a.layTotal.removeClass(W),void(i.page&&(i.page=f.extend({elem:"layui-table-page"+i.index,count:n,limit:i.limit,limits:i.limits||[10,20,30,40,50,60,70,80,90],groups:3,layout:["prev","page","next","skip","count","limit"],prev:'',next:'',jump:function(e,t){t||(a.page=e.curr,i.limit=e.limit,a.pullData(e.curr))}},i.page),i.page.count=n,p.render(i.page)))))},k.renderData=function(e){e=C(e);e&&e.pullData(e.page,{renderData:!0,type:"reloadData"})},n.prototype.renderTotal=function(e,o){var d,r=this,c=r.config,s={};c.totalRow&&(layui.each(e,function(e,i){"array"===layui.type(i)&&0===i.length||r.eachCols(function(e,t){var e=t.field||e,a=i[e];t.totalRow&&(s[e]=(s[e]||0)+(parseFloat(a)||0))})}),r.dataTotal=[],d=[],r.eachCols(function(e,t){var e=t.field||e,a=o&&o[t.field],i="totalRowDecimals"in t?t.totalRowDecimals:2,i=s[e]?parseFloat(s[e]||0).toFixed(i):"",i=(n=t.totalRowText||"",(l={LAY_COL:t})[e]=i,l=t.totalRow&&T.call(r,{item3:t,content:i,tplData:l})||n,a||l),l="string"==typeof(n=t.totalRow||c.totalRow)?m(n).render(f.extend({TOTAL_NUMS:a||s[e],TOTAL_ROW:o||{},LAY_COL:t},t)):i,n=(t.field&&r.dataTotal.push({field:t.field,total:f("
          "+l+"
          ").text()}),['','
          "+l,"
          "].join(""));d.push(n)}),e=r.layTotal.find(".layui-table-patch"),r.layTotal.find("tbody").html(""+d.join("")+(e.length?e.get(0).outerHTML:"")+""))},n.prototype.getColElem=function(e,t){return e.eq(0).find(".laytable-cell-"+t+":eq(0)")},n.prototype.renderForm=function(e){this.config;var t=this.elem.attr("lay-filter");i.render(e,t)},n.prototype.renderFormByElem=function(a){layui.each(["input","select"],function(e,t){i.render(a.find(t))})},n.prototype.syncCheckAll=function(){var a,e=this,i=e.config,t=e.layHeader.find('input[name="layTableCheckbox"]'),l=k.checkStatus(e.key);t[0]&&(a=l.isAll,e.eachCols(function(e,t){"checkbox"===t.type&&(t[i.checkName]=a)}),t.prop({checked:l.isAll,indeterminate:!l.isAll&&l.data.length}))},n.prototype.setRowActive=function(e,t,a){this.config;e=this.layBody.find('tr[data-index="'+e+'"]');if(t=t||"layui-table-click",a)return e.removeClass(t);e.addClass(t),e.siblings("tr").removeClass(t)},n.prototype.setRowChecked=function(i){var a,e,l,t,n,o,d,r=this,c=r.config,s="all"===i.index,u="array"===layui.type(i.index),y=s||u;c.tree&&c.tree.view||y&&(r.layBox.addClass(O),"radio"===i.type)||(u&&(a={},layui.each(i.index,function(e,t){a[t]=!0}),i.index=a),e=r.layBody.children(".layui-table").children("tbody"),d=y?"tr":'tr[data-index="'+i.index+'"]',d=e.children(d),e=s?d:d.filter(u?function(){var e=f(this).data("index");return i.index[e]}:'[data-index="'+i.index+'"]'),i=f.extend({type:"checkbox"},i),l=k.cache[r.key],t="checked"in i,n=function(e){return"radio"===i.type||(t?i.checked:!e)},e.each(function(){var e=f(this),t=e.attr("data-index"),a=l[t];t&&"array"!==layui.type(a)&&!a[c.disabledName]&&(a=a[c.checkName]=n(e.hasClass(A)),e.toggleClass(A,!!a),"radio"===i.type)&&(o=t,e.siblings().removeClass(A))}),o&&layui.each(l,function(e,t){Number(o)!==Number(e)&&delete t[c.checkName]}),d=(u=(s=e.children("td").children(".layui-table-cell").children('input[lay-type="'+({radio:"layTableRadio",checkbox:"layTableCheckbox"}[i.type]||"checkbox")+'"]:not(:disabled)')).last()).closest(I),("radio"===i.type&&d.hasClass(W)?s.first():s).prop("checked",n(u.prop("checked"))),r.syncCheckAll(),y&&setTimeout(function(){r.layBox.removeClass(O)},100))},n.prototype.sort=function(l){var e,t=this,a={},i=t.config,n=i.elem.attr("lay-filter"),o=k.cache[t.key];"string"==typeof(l=l||{}).field&&(d=l.field,t.layHeader.find("th").each(function(e,t){var a=f(this),i=a.data("field");if(i===l.field)return l.field=a,d=i,!1}));try{var d=d||l.field.data("field"),r=l.field.data("key");if(t.sortKey&&!l.pull&&d===t.sortKey.field&&l.type===t.sortKey.sort)return;var c=t.layHeader.find("th .laytable-cell-"+r).find(L);t.layHeader.find("th").find(L).removeAttr("lay-sort"),c.attr("lay-sort",l.type||null),t.layFixed.find("th")}catch(s){b.error("Table modules: sort field '"+d+"' not matched")}t.sortKey={field:d,sort:l.type},i.autoSort&&("asc"===l.type?e=layui.sort(o,d,null,!0):"desc"===l.type?e=layui.sort(o,d,!0,!0):(e=layui.sort(o,k.config.initIndexName,null,!0),delete t.sortKey,delete i.initSort)),a[i.response.dataName]=e||o,t.renderData({res:a,curr:t.page,count:t.count,sort:!0,type:l.reloadType}),l.fromEvent&&(i.initSort={field:d,type:l.type},layui.event.call(l.field,R,"sort("+n+")",f.extend({config:i},i.initSort)))},n.prototype.loading=function(e){this.config.loading&&this.layBox.find(".layui-table-init").toggleClass(W,!e)},n.prototype.cssRules=function(t,a){var e=this.elem.children("style")[0];r.getStyleRules(e,function(e){if(e.selectorText===".laytable-cell-"+t)return a(e),!0})},n.prototype.fullSize=function(){var e,a,i=this,t=i.config,l=t.height;i.fullHeightGap?(l=d.height()-i.fullHeightGap)<135&&(l=135):i.parentDiv&&i.parentHeightGap?(l=f(i.parentDiv).height()-i.parentHeightGap)<135&&(l=135):i.customHeightFunc&&(l=i.customHeightFunc())<135&&(l=135),1
          ')).find("div").css({width:a}),e.find("tr").append(t)):e.find(".layui-table-patch").remove()};n(e.layHeader),n(e.layTotal);n=e.layMain.height()-i;e.layFixed.find(D).css("height",t.height()>=n?n:"auto").scrollTop(e.layMain.scrollTop()),e.layFixRight[k.cache[e.key]&&k.cache[e.key].length&&0
        ');a.html(t),s.height&&a.css("max-height",s.height-(c.layTool.outerHeight()||50)),i.find("."+S)[0]||i.append(a),c.renderForm(),a.on("click",function(e){layui.stope(e)}),e.done&&e.done(a,t)};layui.stope(e),z.trigger("table.tool.panel.remove"),g.close(c.tipsIndex),layui.each(s.defaultToolbar,function(e,t){if(t.layEvent===a)return"function"==typeof t.onClick&&t.onClick({data:l,config:s,openPanel:n,elem:i}),!0}),layui.event.call(this,R,"toolbar("+o+")",f.extend({event:a,config:s},{}))}),c.layHeader.on("click","*[lay-event]",function(e){var t=f(this),a=t.attr("lay-event"),t=t.closest("th").data("key"),t=c.col(t);layui.event.call(this,R,"colTool("+o+")",f.extend({event:a,config:s,col:t},{}))}),c.layPagebar.on("click","*[lay-event]",function(e){var t=f(this).attr("lay-event");layui.event.call(this,R,"pagebar("+o+")",f.extend({event:t,config:s},{}))}),e.on("mousemove",function(e){var t=f(this),a=t.offset().left,e=e.clientX-a;t.data("unresize")||w.eventMoveElem||(r.allowResize=t.width()-e<=10,d.css("cursor",r.allowResize?"col-resize":""))}).on("mouseleave",function(){f(this);w.eventMoveElem||(r.allowResize=!1,d.css("cursor",""))}).on("mousedown",function(e){var t,a=f(this);r.allowResize&&(t=a.data("key"),e.preventDefault(),r.offset=[e.clientX,e.clientY],c.cssRules(t,function(e){var t=e.style.width||a.outerWidth();r.rule=e,r.ruleWidth=parseFloat(t),r.minWidth=a.data("minwidth")||s.cellMinWidth,r.maxWidth=a.data("maxwidth")||s.cellMaxWidth}),a.data(j,r),w.eventMoveElem=a)}),w.docEvent||z.on("mousemove",function(e){var t,a;w.eventMoveElem&&(t=w.eventMoveElem.data(j)||{},w.eventMoveElem.data("resizing",1),e.preventDefault(),t.rule)&&(e=t.ruleWidth+e.clientX-t.offset[0],a=w.eventMoveElem.closest("."+_).attr(N),a=C(a))&&((e=et.maxWidth&&(e=t.maxWidth),t.rule.style.width=e+"px",a.setGroupWidth(w.eventMoveElem),g.close(c.tipsIndex))}).on("mouseup",function(e){var t,a,i,l,n;w.eventMoveElem&&(i=(t=w.eventMoveElem).closest("."+_).attr(N),a=C(i))&&(i=t.data("key"),l=a.col(i),n=a.config.elem.attr("lay-filter"),r={},d.css("cursor",""),a.scrollPatch(),t.removeData(j),delete w.eventMoveElem,a.cssRules(i,function(e){l.width=parseFloat(e.style.width),layui.event.call(t[0],R,"colResized("+n+")",{col:l,config:a.config})}))}),w.docEvent=!0,e.on("click",function(e){var t=f(this),a=t.find(L),i=a.attr("lay-sort");if(!a[0]||1===t.data("resizing"))return t.removeData("resizing");c.sort({field:t,type:"asc"===i?"desc":"desc"===i?null:"asc",fromEvent:!0})}).find(L+" .layui-edge ").on("click",function(e){var t=f(this),a=t.index(),t=t.parents("th").eq(0).data("field");layui.stope(e),0===a?c.sort({field:t,type:"asc",fromEvent:!0}):c.sort({field:t,type:"desc",fromEvent:!0})}),c.commonMember=function(e){var a=f(this).parents("tr").eq(0).data("index"),t=c.layBody.find('tr[data-index="'+a+'"]'),i=(k.cache[c.key]||[])[a]||{},l={tr:t,config:s,data:k.clearCacheKey(i),dataCache:i,index:a,del:function(){k.cache[c.key][a]=[],t.remove(),c.scrollPatch()},update:function(e,t){c.updateRow({index:a,data:e=e||{},related:t},function(e,t){l.data[e]=t})},setRowChecked:function(e){c.setRowChecked(f.extend({index:a},e))}};return f.extend(l,e)}),t=(c.elem.on("click",'input[name="layTableCheckbox"]+',function(e){var t=f(this),a=t.closest("td"),t=t.prev(),i=(c.layBody.find('input[name="layTableCheckbox"]'),t.parents("tr").eq(0).data("index")),l=t[0].checked,n="layTableAllChoose"===t.attr("lay-filter");t[0].disabled||(n?c.setRowChecked({index:"all",checked:l}):c.setRowChecked({index:i,checked:l}),layui.stope(e),layui.event.call(t[0],R,"checkbox("+o+")",y.call(t[0],{checked:l,type:n?"all":"one",getCol:function(){return c.col(a.data("key"))}})))}),c.elem.on("click",'input[lay-type="layTableRadio"]+',function(e){var t=f(this),a=t.closest("td"),t=t.prev(),i=t[0].checked,l=t.parents("tr").eq(0).data("index");if(layui.stope(e),t[0].disabled)return!1;c.setRowChecked({type:"radio",index:l}),layui.event.call(t[0],R,"radio("+o+")",y.call(t[0],{checked:i,getCol:function(){return c.col(a.data("key"))}}))}),c.layBody.on("mouseenter","tr",function(){var e=f(this),t=e.index();e.data("off")||c.layBody.find("tr:eq("+t+")").addClass(M)}).on("mouseleave","tr",function(){var e=f(this),t=e.index();e.data("off")||c.layBody.find("tr:eq("+t+")").removeClass(M)}).on("click","tr",function(e){t.call(this,"row",e)}).on("dblclick","tr",function(e){t.call(this,"rowDouble",e)}).on("contextmenu","tr",function(e){s.defaultContextmenu||e.preventDefault(),t.call(this,"rowContextmenu",e)}),function(e,t){var a=f(this);if(!a.data("off")){if("rowContextmenu"!==e){var i=[".layui-form-checkbox",".layui-form-switch",".layui-form-radio","[lay-unrow]"].join(",");if(f(t.target).is(i)||f(t.target).closest(i)[0])return}layui.event.call(this,R,e+"("+o+")",y.call(a.children("td")[0],{e:t}))}}),n=function(e,t){var a,i,l;(e=f(e)).data("off")||(l=e.data("field"),i=e.data("key"),i=c.col(i),a=e.closest("tr").data("index"),a=k.cache[c.key][a],e.children(u),(i="function"==typeof i.edit?i.edit(a):i.edit)&&((i=f("textarea"===i?'':''))[0].value=(l=e.data("content")||a[l])===undefined||null===l?"":l,e.find("."+E)[0]||e.append(i),i.focus(),t)&&layui.stope(t))},i=(c.layBody.on("change","."+E,function(){var e=f(this),t=e.parent(),a=this.value,i=e.parent().data("field"),e=e.closest("tr").data("index"),e=k.cache[c.key][e],l=y.call(t[0],{value:a,field:i,oldValue:e[i],td:t,reedit:function(){setTimeout(function(){n(l.td);var e={};e[i]=l.oldValue,l.update(e)})},getCol:function(){return c.col(t.data("key"))}}),e={};e[i]=a,l.update(e),layui.event.call(t[0],R,"edit("+o+")",l)}).on("blur","."+E,function(){f(this).remove()}),c.layBody.on(s.editTrigger,"td",function(e){n(this,e)}).on("mouseenter","td",function(){a.call(this)}).on("mouseleave","td",function(){a.call(this,"hide")}),c.layTotal.on("mouseenter","td",function(){a.call(this)}).on("mouseleave","td",function(){a.call(this,"hide")}),"layui-table-grid-down"),a=function(e){var t=f(this),a=t.children(u);t.data("off")||t.parent().hasClass(H)||(e?t.find(".layui-table-grid-down").remove():!(a.prop("scrollWidth")>a.prop("clientWidth")||0
        '))},l=function(e,t){var a=f(this),i=a.parent(),l=i.data("key"),n=c.col(l),o=i.parent().data("index"),d=i.children(u),i="layui-table-cell-c",r=f('');"tips"===(t=t||n.expandedMode||s.cellExpandedMode)?c.tipsIndex=g.tips(['
        ',d.html(),"
        ",''].join(""),d[0],{tips:[3,""],time:-1,anim:-1,maxWidth:x.ios||x.android?300:c.elem.width()/2,isOutAnim:!1,skin:"layui-table-tips",success:function(e,t){e.find(".layui-table-tips-c").on("click",function(){g.close(t)})}}):(c.elem.find("."+i).trigger("click"),c.cssRules(l,function(e){var t=e.style.width,a=n.expandedWidth||s.cellExpandedWidth;atr").each(function(i){n.cols[i]=[],f(this).children().each(function(e){var t=f(this),a=t.attr("lay-data"),a=r.options(this,{attr:a?"lay-data":null,errorText:d+(a||t.attr("lay-options"))}),t=f.extend({title:t.text(),colspan:parseInt(t.attr("colspan"))||1,rowspan:parseInt(t.attr("rowspan"))||1},a);n.cols[i].push(t)})}),e.find("tbody>tr")),t=k.render(n);!a.length||o.data||t.config.url||(l=0,k.eachCols(t.config.id,function(e,i){a.each(function(e){n.data[e]=n.data[e]||{};var t=f(this),a=i.field;n.data[e][a]=t.children("td").eq(l).html()}),l++}),t.reloadData({data:n.data}))}),this},w.that={},w.config={},function(a,i,e,l){var n,o;l.colGroup&&(n=0,a++,l.CHILD_COLS=[],o=e+(parseInt(l.rowspan)||1),layui.each(i[o],function(e,t){t.parentKey?t.parentKey===l.key&&(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),c(a,i,o,t)):t.PARENT_COL_INDEX||1<=n&&n==(l.colspan||1)||(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),n+=parseInt(1td').filter('[data-field="'+e+'"]')}}})).replace(/"/g,'""'),n.push(a='"'+a+'"')):t.field&&"normal"!==t.type&&0==i&&(u[t.field]=!0)}),c.push(n.join(","))}),o&&layui.each(o.dataTotal,function(e,t){u[t.field]||s.push('"'+(t.total||"")+'"')}),r.join(",")+"\r\n"+c.join("\r\n")+"\r\n"+s.join(","))),d.download=(a.title||l.title||"table_"+(l.index||""))+"."+i,document.body.appendChild(d),d.click(),document.body.removeChild(d)},k.getOptions=l,k.hideCol=function(e,l){var n=C(e);n&&("boolean"===layui.type(l)?n.eachCols(function(e,t){var a=t.key,i=n.col(a),t=t.parentKey;i.hide!=l&&(i=i.hide=l,n.elem.find('*[data-key="'+a+'"]')[i?"addClass":"removeClass"](W),n.setParentCol(i,t))}):(l=layui.isArray(l)?l:[l],layui.each(l,function(e,l){n.eachCols(function(e,t){var a,i;l.field===t.field&&(a=t.key,i=n.col(a),t=t.parentKey,"hide"in l)&&i.hide!=l.hide&&(i=i.hide=!!l.hide,n.elem.find('*[data-key="'+a+'"]')[i?"addClass":"removeClass"](W),n.setParentCol(i,t))})})),f("."+S).remove(),n.resize())},k.reload=function(e,t,a,i){if(l(e))return(e=C(e)).reload(t,a,i),w.call(e)},k.reloadData=function(){var a=f.extend([],arguments),i=(a[3]="reloadData",new RegExp("^("+["elem","id","cols","width","height","maxHeight","toolbar","defaultToolbar","className","css","pagebar"].join("|")+")$"));return layui.each(a[1],function(e,t){i.test(e)&&delete a[1][e]}),k.reload.apply(null,a)},k.render=function(e){e=new n(e);return w.call(e)},k.clearCacheKey=function(e){return delete(e=f.extend({},e))[k.config.checkName],delete e[k.config.indexName],delete e[k.config.initIndexName],delete e[k.config.numbersName],delete e[k.config.disabledName],e},f(function(){k.init()}),s(R,k)});layui.define(["table"],function(e){"use strict";var P=layui.$,h=layui.form,B=layui.table,y=layui.hint(),j={config:{},on:B.on,eachCols:B.eachCols,index:B.index,set:function(e){var t=this;return t.config=P.extend({},t.config,e),t},resize:B.resize,getOptions:B.getOptions,hideCol:B.hideCol,renderData:B.renderData},i=function(){var a=this,e=a.config,n=e.id||e.index;return{config:e,reload:function(e,t){a.reload.call(a,e,t)},reloadData:function(e,t){j.reloadData(n,e,t)}}},F=function(e){var t=i.that[e];return t||y.error(e?"The treeTable instance with ID '"+e+"' not found":"ID argument required"),t||null},L="lay-table-id",q="layui-hide",s=".layui-table-body",R=".layui-table-main",Y=".layui-table-fixed-l",z=".layui-table-fixed-r",l="layui-table-checked",m="layui-table-tree",H="LAY_DATA_INDEX",b="LAY_DATA_INDEX_HISTORY",p="LAY_PARENT_INDEX",g="LAY_CHECKBOX_HALF",X="LAY_EXPAND",V="LAY_HAS_EXPANDED",U="LAY_ASYNC_STATUS",n=["all","parent","children","none"],t=/<[^>]+?>/,f=["flexIconClose","flexIconOpen","iconClose","iconOpen","iconLeaf","icon"],a=function(e){var t=this;t.index=++j.index,t.config=P.extend(!0,{},t.config,j.config,e),t.init(),t.render()},x=function(n,i,e){var l=B.cache[n];layui.each(e||l,function(e,t){var a=t[H]||"";-1!==a.indexOf("-")&&(l[a]=t),t[i]&&x(n,i,t[i])})},d=function(d,a,e){var r=F(d),o=("reloadData"!==e&&(r.status={expand:{}}),P.extend(!0,{},r.getOptions(),a)),n=o.tree,c=n.customName.children,i=n.customName.id,l=(delete a.hasNumberCol,delete a.hasChecboxCol,delete a.hasRadioCol,B.eachCols(null,function(e,t){"numbers"===t.type?a.hasNumberCol=!0:"checkbox"===t.type?a.hasChecboxCol=!0:"radio"===t.type&&(a.hasRadioCol=!0)},o.cols),a.parseData),u=a.done;"reloadData"===e&&"fixed"===o.scrollPos&&(r.scrollTopCache=r.config.elem.next().find(s).scrollTop()),o.url?e&&(!l||l.mod)||(a.parseData=function(){var e=this,t=arguments,a=t[0],t=("function"===layui.type(l)&&(a=l.apply(e,t)||t[0]),e.response.dataName);return n.data.isSimpleData&&!n["async"].enable&&(a[t]=r.flatToTree(a[t])),N(a[t],function(e){e[X]=X in e?e[X]:e[i]!==undefined&&r.status.expand[e[i]]},c),e.autoSort&&e.initSort&&e.initSort.type&&layui.sort(a[t],e.initSort.field,"desc"===e.initSort.type,!0),r.initData(a[t]),a},a.parseData.mod=!0):a.data!==undefined&&(a.data=a.data||[],n.data.isSimpleData&&(a.data=r.flatToTree(a.data)),r.initData(a.data)),e&&(!u||u.mod)||(a.done=function(){var e,t=arguments,a=t[3],n="renderData"===a,i=(n||delete r.isExpandAll,this.elem.next()),l=(r.updateStatus(null,{LAY_HAS_EXPANDED:!1}),x(d,c),i.find('[name="layTableCheckbox"][lay-filter="layTableAllChoose"]'));if(l.length&&(e=j.checkStatus(d),l.prop({checked:e.isAll&&e.data.length,indeterminate:!e.isAll&&e.data.length})),!n&&o.autoSort&&o.initSort&&o.initSort.type&&j.sort(d),r.renderTreeTable(i),"reloadData"===a&&"fixed"===this.scrollPos&&i.find(s).scrollTop(r.scrollTopCache),"function"===layui.type(u))return u.apply(this,t)},a.done.mod=!0),a&&a.tree&&a.tree.view&&layui.each(f,function(e,t){a.tree.view[t]!==undefined&&(a.tree.view[t]=r.normalizedIcon(a.tree.view[t]))})};a.prototype.init=function(){var e=this.config,t=e.tree.data.cascade,t=(-1===n.indexOf(t)&&(e.tree.data.cascade="all"),B.render(P.extend({},e,{data:[],url:"",done:null}))),a=t.config.id;(i.that[a]=this).tableIns=t,d(a,e)},a.prototype.config={tree:{customName:{children:"children",isParent:"isParent",name:"name",id:"id",pid:"parentId",icon:"icon"},view:{indent:14,flexIconClose:'',flexIconOpen:'',showIcon:!0,icon:"",iconClose:'',iconOpen:'',iconLeaf:'',showFlexIconIfNotParent:!1,dblClickExpand:!0,expandAllDefault:!1},data:{isSimpleData:!1,rootPid:null,cascade:"all"},"async":{enable:!1,url:"",type:null,contentType:null,headers:null,where:null,autoParam:[]},callback:{beforeExpand:null,onExpand:null}}},a.prototype.normalizedIcon=function(e){return e?t.test(e)?e:'':""},a.prototype.getOptions=function(){return this.tableIns?B.getOptions(this.tableIns.config.id):this.config},a.prototype.flatToTree=function(e){var n,i,l,d,r,o,c,u,t=this.getOptions(),a=t.tree,s=a.customName,t=t.id;return e=e||B.cache[t],t=e,n=s.id,i=s.pid,l=s.children,d=a.data.rootPid,n=n||"id",i=i||"parentId",l=l||"children",c={},u=[],layui.each(t,function(e,t){r=n+t[n],o=n+t[i],c[r]||(c[r]={},c[r][l]=[]);var a={};a[l]=c[r][l],c[r]=P.extend({},t,a),((d?c[r][i]===d:!c[r][i])?u:(c[o]||(c[o]={},c[o][l]=[]),c[o][l])).push(c[r])}),u},a.prototype.treeToFlat=function(e,n,i){var l=this,d=l.getOptions().tree.customName,r=d.children,o=d.pid,c=[];return layui.each(e,function(e,t){var e=(i?i+"-":"")+e,a=P.extend({},t);a[o]="undefined"!=typeof t[o]?t[o]:n,c.push(a),c=c.concat(l.treeToFlat(t[r],t[d.id],e))}),c},a.prototype.getTreeNode=function(e){var t,a,n=this;return e?(a=(t=n.getOptions()).tree,t.id,a.customName,{data:e,dataIndex:e[H],getParentNode:function(){return n.getNodeByIndex(e[p])}}):y.error("\u627e\u4e0d\u5230\u8282\u70b9\u6570\u636e")},a.prototype.getNodeByIndex=function(t){var a,e,n=this,i=n.getNodeDataByIndex(t);return i?((e=n.getOptions()).tree.customName.parent,a=e.id,(e={data:i,dataIndex:i[H],getParentNode:function(){return n.getNodeByIndex(i[p])},update:function(e){return j.updateNode(a,t,e)},remove:function(){return j.removeNode(a,t)},expand:function(e){return j.expandNode(a,P.extend({},e,{index:t}))},setChecked:function(e){return j.setRowChecked(a,P.extend({},e,{index:t}))}}).dataIndex=t,e):y.error("\u627e\u4e0d\u5230\u8282\u70b9\u6570\u636e")},a.prototype.getNodeById=function(a){var e=this.getOptions(),n=e.tree.customName.id,i="",e=j.getData(e.id,!0);if(layui.each(e,function(e,t){if(t[n]===a)return i=t[H],!0}),i)return this.getNodeByIndex(i)},a.prototype.getNodeDataByIndex=function(e,t,a){var n=this.getOptions(),i=n.tree,n=n.id,n=B.cache[n],l=n[e];if("delete"!==a&&l)return P.extend(l,a),t?P.extend({},l):l;for(var d=n,r=String(e).split("-"),o=0,c=i.customName.children;o
        '),I=function(e){p[U]="success",p[f.children]=e,u.initData(p[f.children],p[H]),K(t,!0,!x&&n,i,l,d)},D=b.format,"function"===layui.type(D)?D(p,c,I):(C=P.extend({},b.where||c.where),D=b.autoParam,layui.each(D,function(e,t){t=t.split("=");C[t[0].trim()]=p[(t[1]||t[0]).trim()]}),(D=b.contentType||c.contentType)&&0==D.indexOf("application/json")&&(C=JSON.stringify(C)),S=b.method||c.method,T=b.dataType||c.dataType,_=b.jsonpCallback||c.jsonpCallback,k=b.headers||c.headers,w=b.parseData||c.parseData,O=b.response||c.response,P.ajax({type:S||"get",url:g,contentType:D,data:C,dataType:T||"json",jsonpCallback:_,headers:k||{},success:function(e){(e="function"==typeof w?w.call(c,e)||e:e)[O.statusName]!=O.statusCode?(p[U]="error",p[X]=!1,v.html('')):I(e[O.dataName])},error:function(e,t){p[U]="error",p[X]=!1,"function"==typeof c.error&&c.error(e,t)}})),m;p[V]=!0,N.length&&(!c.initSort||c.url&&!c.autoSort||((b=c.initSort).type?layui.sort(N,b.field,"desc"===b.type,!0):layui.sort(N,B.config.indexName,null,!0)),u.initData(p[f.children],p[H]),S=B.getTrHtml(o,N,null,null,e),E={trs:P(S.trs.join("")),trs_fixed:P(S.trs_fixed.join("")),trs_fixed_r:P(S.trs_fixed_r.join(""))},A=(e.split("-").length-1||0)+1,layui.each(N,function(e,t){E.trs.eq(e).attr({"data-index":t[H],"lay-data-index":t[H],"data-level":A}).data("index",t[H]),E.trs_fixed.eq(e).attr({"data-index":t[H],"lay-data-index":t[H],"data-level":A}).data("index",t[H]),E.trs_fixed_r.eq(e).attr({"data-index":t[H],"lay-data-index":t[H],"data-level":A}).data("index",t[H])}),r.find(R).find('tbody tr[lay-data-index="'+e+'"]').after(E.trs),r.find(Y).find('tbody tr[lay-data-index="'+e+'"]').after(E.trs_fixed),r.find(z).find('tbody tr[lay-data-index="'+e+'"]').after(E.trs_fixed_r),u.renderTreeTable(E.trs,A),n)&&!x&&layui.each(N,function(e,t){K({dataIndex:t[H],trElem:r.find('tr[lay-data-index="'+t[H]+'"]').first(),tableViewElem:r,tableId:o,options:c},a,n,i,l,d)})}else u.isExpandAll=!1,(n&&!x?(layui.each(N,function(e,t){K({dataIndex:t[H],trElem:r.find('tr[lay-data-index="'+t[H]+'"]').first(),tableViewElem:r,tableId:o,options:c},a,n,i,l,d)}),r.find(N.map(function(e,t,a){return'tr[lay-data-index="'+e[H]+'"]'}).join(","))):(g=u.treeToFlat(N,p[f.id],e),r.find(g.map(function(e,t,a){return'tr[lay-data-index="'+e[H]+'"]'}).join(",")))).addClass(q);J("resize-"+o,function(){j.resize(o)},0)(),l&&"loading"!==p[U]&&(D=s.callback.onExpand,"function"===layui.type(D))&&D(o,p,h),"function"===layui.type(d)&&"loading"!==p[U]&&d(o,p,h)}return m},v=(j.expandNode=function(e,t){var a,n,i,l,e=F(e);if(e)return a=(t=t||{}).index,n=t.expandFlag,i=t.inherit,l=t.callbackFlag,e=e.getOptions().elem.next(),K({trElem:e.find('tr[lay-data-index="'+a+'"]').first()},n,i,null,l,t.done)},j.expandAll=function(a,e){if("boolean"!==layui.type(e))return y.error("expandAll \u7684\u5c55\u5f00\u72b6\u6001\u53c2\u6570\u53ea\u63a5\u6536true/false");var t=F(a);if(t){t.isExpandAll=e;var n=t.getOptions(),i=n.tree,l=n.elem.next(),d=i.customName.isParent,r=i.customName.id,o=i.view.showFlexIconIfNotParent;if(e){e=j.getData(a,!0);if(i["async"].enable){var c=!0;if(layui.each(e,function(e,t){if(t[d]&&!t[U])return!(c=!1)}),!c)return void layui.each(j.getData(a),function(e,t){j.expandNode(a,{index:t[H],expandFlag:!0,inherit:!0})})}var u=!0;if(layui.each(e,function(e,t){if(t[d]&&!t[V])return!(u=!1)}),u)t.updateStatus(null,function(e){(e[d]||o)&&(e[X]=!0,e[r]!==undefined)&&(t.status.expand[e[r]]=!0)}),l.find('tbody tr[data-level!="0"]').removeClass(q),l.find(".layui-table-tree-flexIcon").html(i.view.flexIconOpen),i.view.showIcon&&l.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)").html(i.view.iconOpen);else{if(t.updateStatus(null,function(e){(e[d]||o)&&(e[X]=!0,e[V]=!0,e[r]!==undefined)&&(t.status.expand[e[r]]=!0)}),n.initSort&&n.initSort.type&&n.autoSort)return j.sort(a);var s,n=B.getTrHtml(a,e),f={trs:P(n.trs.join("")),trs_fixed:P(n.trs_fixed.join("")),trs_fixed_r:P(n.trs_fixed_r.join(""))};layui.each(e,function(e,t){var a=t[H].split("-").length-1;s={"data-index":t[H],"lay-data-index":t[H],"data-level":a},f.trs.eq(e).attr(s).data("index",t[H]),f.trs_fixed.eq(e).attr(s).data("index",t[H]),f.trs_fixed_r.eq(e).attr(s).data("index",t[H])}),layui.each(["main","fixed-l","fixed-r"],function(e,t){l.find(".layui-table-"+t+" tbody").html(f[["trs","trs_fixed","trs_fixed_r"][e]])}),t.renderTreeTable(l,0,!1)}}else t.updateStatus(null,function(e){(e[d]||o)&&(e[X]=!1,e[r]!==undefined)&&(t.status.expand[e[r]]=!1)}),l.find('.layui-table-box tbody tr[data-level!="0"]').addClass(q),l.find(".layui-table-tree-flexIcon").html(i.view.flexIconClose),i.view.showIcon&&l.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)").html(i.view.iconClose);j.resize(a)}},a.prototype.updateNodeIcon=function(e){var t=this.getOptions().tree||{},a=e.scopeEl,n=e.isExpand,e=e.isParent;a.find(".layui-table-tree-flexIcon").css("visibility",e||t.view.showFlexIconIfNotParent?"visible":"hidden").html(n?t.view.flexIconOpen:t.view.flexIconClose),t.view.showIcon&&(a=a.find(".layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom)"),n=e?n?t.view.iconOpen:t.view.iconClose:t.view.iconLeaf,a.toggleClass("layui-table-tree-iconLeaf",!e).html(n))},a.prototype.renderTreeTable=function(e,t,a){var l=this,n=l.getOptions(),d=n.elem.next(),i=(d.hasClass(m)||d.addClass(m),n.id),r=n.tree||{},o=(r.data,r.view||{}),c=r.customName||{},u=c.isParent,s=(d.attr("lay-filter"),l),f=n.data.length,y=((t=t||0)||(d.find(".layui-table-body tr:not([data-level])").attr("data-level",t),layui.each(B.cache[i],function(e,t){f&&(t[H]=String(e));t=t[H];d.find('.layui-table-main tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t),d.find('.layui-table-fixed-l tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t),d.find('.layui-table-fixed-r tbody tr[data-level="0"]:eq('+e+")").attr("lay-data-index",t)})),null),p=c.name,x=o.indent||14;if(layui.each(e.find('td[data-field="'+p+'"]'),function(e,t){var a,n,i=(t=P(t)).closest("tr"),t=t.children(".layui-table-cell");t.hasClass("layui-table-tree-item")||(n=i.attr("lay-data-index"))&&(i=d.find('tr[lay-data-index="'+n+'"]'),(a=s.getNodeDataByIndex(n))[X]&&a[u]&&((y=y||{})[n]=!0),a[g]&&i.find('input[type="checkbox"][name="layTableCheckbox"]').prop("indeterminate",!0),n=t.html(),(t=i.find('td[data-field="'+p+'"]>div.layui-table-cell')).addClass("layui-table-tree-item"),t.html(['
        ',a[X]?o.flexIconOpen:o.flexIconClose,"
        ",o.showIcon?'
        '+(l.normalizedIcon(a[c.icon])||o.icon||(a[u]?a[X]?o.iconOpen:o.iconClose:o.iconLeaf)||"")+"
        ":"",n].join("")).find(".layui-table-tree-flexIcon").on("click",function(e){layui.stope(e),K({trElem:i},null,null,null,!0)}))}),!t&&r.view.expandAllDefault&&l.isExpandAll===undefined)return j.expandAll(i,!0);(!1!==a&&y?(layui.each(y,function(e,t){e=d.find('tr[lay-data-index="'+e+'"]');e.find(".layui-table-tree-flexIcon").html(o.flexIconOpen),K({trElem:e.first()},!0)}),J("renderTreeTable2-"+i,function(){h.render(P(".layui-table-tree["+L+'="'+i+'"]'))},0)):J("renderTreeTable-"+i,function(){n.hasNumberCol&&v(l),h.render(P(".layui-table-tree["+L+'="'+i+'"]'))},0))()},function(a){var e=a.getOptions(),t=e.elem.next(),n=0,i=t.find(".layui-table-main tbody tr"),l=t.find(".layui-table-fixed-l tbody tr"),d=t.find(".layui-table-fixed-r tbody tr");layui.each(a.treeToFlat(B.cache[e.id]),function(e,t){t.LAY_HIDE||(a.getNodeDataByIndex(t[H]).LAY_NUM=++n,i.eq(e).find(".laytable-cell-numbers").html(n),l.eq(e).find(".laytable-cell-numbers").html(n),d.eq(e).find(".laytable-cell-numbers").html(n))})}),N=(a.prototype.render=function(e){var t=this;t.tableIns=B["reloadData"===e?"reloadData":"reload"](t.tableIns.config.id,P.extend(!0,{},t.config)),t.config=t.tableIns.config},a.prototype.reload=function(e,t,a){var n=this;e=e||{},delete n.haveInit,layui.each(e,function(e,t){"array"===layui.type(t)&&delete n.config[e]}),d(n.getOptions().id,e,a||!0),n.config=P.extend(t,{},n.config,e),n.render(a)},j.reloadData=function(){var e=P.extend(!0,[],arguments);return e[3]="reloadData",j.reload.apply(null,e)},function(e,a,n,i){var l=[];return layui.each(e,function(e,t){"function"===layui.type(a)?a(t):P.extend(t,a),l.push(P.extend({},t)),i||(l=l.concat(N(t[n],a,n,i)))}),l}),o=(a.prototype.updateStatus=function(e,t,a){var n=this.getOptions(),i=n.tree;return e=e||B.cache[n.id],N(e,t,i.customName.children,a)},a.prototype.getTableData=function(){var e=this.getOptions();return B.cache[e.id]},j.updateStatus=function(e,t,a){var e=F(e),n=e.getOptions();return a=a||(n.url?B.cache[n.id]:n.data),e.updateStatus(a,t)},j.sort=function(e){var t,a,i,l,n,d=F(e);d&&(n=(t=d.getOptions()).tree,a=j.getData(e),i=n.customName.children,l=function(e,a,n){layui.sort(e,a,n,!0),layui.each(e,function(e,t){l(t[i]||[],a,n)})},t.autoSort)&&((n=t.initSort).type?l(a,n.field,"desc"===n.type):l(a,B.config.indexName,null),B.cache[e]=a,d.initData(a),j.renderData(e))},function(n){var t=n.config.id,i=F(t),a=n.data=j.getNodeDataByIndex(t,n.index),l=a[H],d=(n.dataIndex=l,n.update);n.update=function(){var e=arguments,t=(P.extend(i.getNodeDataByIndex(l),e[0]),d.apply(this,e)),a=n.config.tree.customName.name;return a in e[0]&&n.tr.find('td[data-field="'+a+'"]').children("div.layui-table-cell").removeClass("layui-table-tree-item"),i.renderTreeTable(n.tr,n.tr.attr("data-level"),!1),t},n.del=function(){j.removeNode(t,a)},n.setRowChecked=function(e){j.setRowChecked(t,{index:a,checked:e})}}),u=(j.updateNode=function(e,a,t){var n,i,l,d,r,o=F(e);o&&((d=o.getOptions()).tree,d=(n=d.elem.next()).find('tr[lay-data-index="'+a+'"]'),i=d.attr("data-index"),l=d.attr("data-level"),t)&&(d=o.getNodeDataByIndex(a,!1,t),r=B.getTrHtml(e,[d]),layui.each(["main","fixed-l","fixed-r"],function(e,t){n.find(".layui-table-"+t+' tbody tr[lay-data-index="'+a+'"]').replaceWith(P(r[["trs","trs_fixed","trs_fixed_r"][e]].join("")).attr({"data-index":i,"lay-data-index":a,"data-level":l}).data("index",i))}),o.renderTreeTable(n.find('tr[lay-data-index="'+a+'"]'),l))},j.removeNode=function(e,t,a){var n=F(e);if(n){var i,l=n.getOptions(),d=l.tree,r=d.customName.isParent,o=d.customName.children,c=l.elem.next(),u=[],s=B.cache[e],t=n.getNodeDataByIndex("string"===layui.type(t)?t:t[H],!1,"delete"),f=n.getNodeDataByIndex(t[p]),d=(n.updateCheckStatus(f),n.treeToFlat([t],t[d.customName.pid],t[p])),t=(layui.each(d,function(e,t){t=t[H];u.push('tr[lay-data-index="'+t+'"]'),-1!==t.indexOf("-")&&delete s[t]}),c.find(u.join(",")).remove(),n.initData());for(i in s)-1!==i.indexOf("-")&&i!==s[i][H]&&delete s[i];layui.each(n.treeToFlat(t),function(e,t){t[b]&&t[b]!==t[H]&&c.find('tr[lay-data-index="'+t[b]+'"]').attr({"data-index":t[H],"lay-data-index":t[H]}).data("index",t[H])}),layui.each(s,function(e,t){c.find('tr[data-level="0"][lay-data-index="'+t[H]+'"]').attr("data-index",e).data("index",e)}),l.hasNumberCol&&v(n),f&&(d=c.find('tr[lay-data-index="'+f[H]+'"]'),a||(f[r]=!(!f[o]||!f[o].length)),n.updateNodeIcon({scopeEl:d,isExpand:f[X],isParent:f[r]})),j.resize(e)}},j.addNodes=function(e,t){var a=F(e);if(a){var n=a.getOptions(),i=n.tree,l=n.elem.next(),d=B.config.checkName,r=(t=t||{}).parentIndex,o=t.index,c=t.data,t=t.focus,u=(r="number"===layui.type(r)?r.toString():r)?a.getNodeDataByIndex(r):null,o="number"===layui.type(o)?o:-1,c=P.extend(!0,[],layui.isArray(c)?c:[c]);layui.each(c,function(e,t){d in t||!u||(t[d]=u[d])}),a.getTableData();if(u){var s=i.customName.isParent,f=i.customName.children;u[s]=!0;var y=(y=u[f])?(p=y.splice(-1===o?y.length:o),u[f]=y.concat(c,p)):u[f]=c,f=(a.updateStatus(y,function(e){(e[s]||i.view.showFlexIconIfNotParent)&&(e[V]=!1)}),a.treeToFlat(y));l.find(f.map(function(e){return'tr[lay-data-index="'+e[H]+'"]'}).join(",")).remove(),a.initData(),u[V]=!1,u[U]="local",K({trElem:l.find('tr[lay-data-index="'+r+'"]')},!0)}else{var p=B.cache[e].splice(-1===o?B.cache[e].length:o);if(B.cache[e]=B.cache[e].concat(c,p),n.url||(n.page?(y=n.page,n.data.splice.apply(n.data,[y.limit*(y.curr-1),y.limit].concat(B.cache[e]))):n.data=B.cache[e]),a.initData(),l.find(".layui-none").length)return B.renderData(e),c;var x,f=B.getTrHtml(e,c),h={trs:P(f.trs.join("")),trs_fixed:P(f.trs_fixed.join("")),trs_fixed_r:P(f.trs_fixed_r.join(""))},r=(layui.each(c,function(e,t){x={"data-index":t[H],"lay-data-index":t[H],"data-level":"0"},h.trs.eq(e).attr(x).data("index",t[H]),h.trs_fixed.eq(e).attr(x).data("index",t[H]),h.trs_fixed_r.eq(e).attr(x).data("index",t[H])}),parseInt(c[0][H])-1),y=l.find(R),n=l.find(Y),f=l.find(z);-1==r?y.find('tr[data-level="0"][data-index="0"]')[0]?(y.find('tr[data-level="0"][data-index="0"]').before(h.trs),n.find('tr[data-level="0"][data-index="0"]').before(h.trs_fixed),f.find('tr[data-level="0"][data-index="0"]').before(h.trs_fixed_r)):(y.find("tbody").prepend(h.trs),n.find("tbody").prepend(h.trs_fixed),f.find("tbody").prepend(h.trs_fixed_r)):-1===o?(y.find("tbody").append(h.trs),n.find("tbody").append(h.trs_fixed),f.find("tbody").append(h.trs_fixed_r)):(r=p[0][b],y.find('tr[data-level="0"][data-index="'+r+'"]').before(h.trs),n.find('tr[data-level="0"][data-index="'+r+'"]').before(h.trs_fixed),f.find('tr[data-level="0"][data-index="'+r+'"]').before(h.trs_fixed_r)),layui.each(B.cache[e],function(e,t){l.find('tr[data-level="0"][lay-data-index="'+t[H]+'"]').attr("data-index",e).data("index",e)}),a.renderTreeTable(l.find(c.map(function(e,t,a){return'tr[lay-data-index="'+e[H]+'"]'}).join(",")))}return a.updateCheckStatus(u),u&&(o=l.find('tr[lay-data-index="'+u[H]+'"]'),a.updateNodeIcon({scopeEl:o,isExpand:u[X],isParent:u[s]})),j.resize(e),t&&l.find(R).find('tr[lay-data-index="'+c[0][H]+'"]').get(0).scrollIntoViewIfNeeded(),c}},j.checkStatus=function(e,n){var i,t,a,l=F(e);if(l)return l=l.getOptions().tree,i=B.config.checkName,t=j.getData(e,!0).filter(function(e,t,a){return e[i]||n&&e[g]}),a=!0,layui.each("all"===l.data.cascade?B.cache[e]:j.getData(e,!0),function(e,t){if(!t[i])return!(a=!1)}),{data:t,isAll:a}},j.on("sort",function(e){var e=e.config,t=e.elem.next(),e=e.id;t.hasClass(m)&&j.sort(e)}),j.on("row",function(e){e.config.elem.next().hasClass(m)&&o(e)}),j.on("rowDouble",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(m)&&(o(e),(t.tree||{}).view.dblClickExpand)&&K({trElem:e.tr.first()},null,null,null,!0)}),j.on("rowContextmenu",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(m)&&o(e)}),j.on("tool",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(m)&&o(e)}),j.on("edit",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(m)&&(o(e),e.field===t.tree.customName.name)&&((a={})[e.field]=e.value,e.update(a))}),j.on("radio",function(e){var t=e.config,a=t.elem.next(),t=t.id;a.hasClass(m)&&(a=F(t),o(e),u.call(a,e.tr,e.checked))}),a.prototype.setRowCheckedClass=function(e,t){var a=this.getOptions(),n=(e.data("index"),a.elem.next());e[t?"addClass":"removeClass"](l),e.each(function(){var e=P(this).data("index");n.find('.layui-table-fixed-r tbody tr[data-index="'+e+'"]')[t?"addClass":"removeClass"](l)})},a.prototype.updateCheckStatus=function(e,t){var a,n,i,l,d,r,o,c=this,u=c.getOptions();return!!u.hasChecboxCol&&(a=u.tree,n=u.id,i=u.elem.next(),l=B.config.checkName,"all"!==(d=a.data.cascade)&&"parent"!==d||!e||(d=c.updateParentCheckStatus(e,"boolean"===layui.type(t)?t:null),layui.each(d,function(e,t){var a=i.find('tr[lay-data-index="'+t[H]+'"] input[name="layTableCheckbox"]:not(:disabled)'),n=t[l];c.setRowCheckedClass(a.closest("tr"),n),a.prop({checked:n,indeterminate:t[g]})})),o=!(r=!0),0<(e=(e="all"===a.data.cascade?B.cache[n]:j.getData(n,!0)).filter(function(e){return!e[u.disabledName]})).length?layui.each(e,function(e,t){if((t[l]||t[g])&&(o=!0),t[l]||(r=!1),o&&!r)return!0}):r=!1,o=o&&!r,i.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({checked:r,indeterminate:o}),r)},a.prototype.updateParentCheckStatus=function(a,n){var i,e=this.getOptions(),t=e.tree,e=e.id,l=B.config.checkName,t=t.customName.children,d=[];return!(a[g]=!1)===n?a[t].length?layui.each(a[t],function(e,t){if(!t[l])return n=!1,a[g]=!0}):n=!1:!1===n?layui.each(a[t],function(e,t){if(t[l]||t[g])return a[g]=!0}):(n=!1,i=0,layui.each(a[t],function(e,t){t[l]&&i++}),n=a[t].length?a[t].length===i:a[l],a[g]=!n&&0li"],n.bodyElem=["."+C.CONST.BODY+":eq(0)",">."+C.CONST.ITEM],n.getContainer=function(){var e=n.documentElem||t.elem;return{header:{elem:e.find(n.headerElem[0]),items:e.find(n.headerElem.join(""))},body:{elem:e.find(n.bodyElem[0]),items:e.find(n.bodyElem.join(""))}}},"array"===layui.type(t.header)?"string"==typeof t.header[0]?(n.headerElem=t.header.concat(),n.documentElem=p(document)):(n.elemView=p('
        '),t.className&&n.elemView.addClass(t.className),a=p('
          '),i=p('
          '),layui.each(t.header,function(e,t){t=n.renderHeaderItem(t);a.append(t)}),layui.each(t.body,function(e,t){t=n.renderBodyItem(t);i.append(t)}),n.elemView.append(a).append(i),t.elem.html(n.elemView)):n.renderClose(),"array"===layui.type(t.body)&&"string"==typeof t.body[0]&&(n.documentElem=p(document),n.bodyElem=t.body.concat()),n.data());"index"in t&&e.index!=t.index?n.change(n.findHeaderItem(t.index),!0):-1===e.index&&n.change(n.findHeaderItem(0),!0),n.roll("auto"),t.elem.hasClass(C.CONST.CLASS_HIDEV)&&t.elem.removeClass(C.CONST.CLASS_HIDEV),"function"==typeof t.afterRender&&t.afterRender(e),layui.event.call(t.elem[0],C.CONST.MOD_NAME,"afterRender("+t.id+")",e)},events:function(){var e,t=this,a=t.config,i=t.getContainer(),n=C.CONST.MOD_NAME,i=(t.documentElem?i.header:a).elem,a=a.trigger+(".lay_"+n+"_trigger"),n=t.documentElem?t.headerElem[1]:t.headerElem.join("");i.off(a).on(a,n,function(){t.change(p(this))}),r.onresize||(p(window).on("resize",function(){clearTimeout(e),e=setTimeout(function(){layui.each(C.cache.id,function(e){e=C.getInst(e);e&&e.roll("init")})},50)}),r.onresize=!0)}}),r={},t=C.Class;t.prototype.add=function(e){var t,a,i=this,n=(i.config,i.getContainer()),r=i.renderHeaderItem(e),d=i.renderBodyItem(e),o=i.data();e=p.extend({active:!0},e),/(before|after)/.test(e.mode)?(a=(t=e.hasOwnProperty("index"))?i.findHeaderItem(e.index):o.thisHeaderItem,t=t?i.findBodyItem(e.index):o.thisHeaderItem,a[e.mode](r),t[e.mode](d)):(a={prepend:"prepend",append:"append"}[e.mode||"append"]||"append",n.header.elem[a](r),n.body.elem[a](d)),e.active?i.change(r,!0):i.roll("auto"),"function"==typeof e.done&&e.done(p.extend(o,{headerItem:r,bodyItem:d}))},t.prototype.close=function(e,t){if(e&&e[0]){var a=this,i=a.config,n=e.attr("lay-id"),r=e.index();if("false"!==e.attr("lay-closable")){var d=a.data();if(!t)if(!1===layui.event.call(e[0],C.CONST.MOD_NAME,"beforeClose("+i.id+")",p.extend(d,{index:r})))return;e.hasClass(C.CONST.CLASS_THIS)&&(e.next()[0]?a.change(e.next(),!0):e.prev()[0]&&a.change(e.prev(),!0)),a.findBodyItem(n||r).remove(),e.remove(),a.roll("auto",r);d=a.data();layui.event.call(d.thisHeaderItem[0],C.CONST.MOD_NAME,"afterClose("+i.id+")",d)}}},t.prototype.closeMult=function(i,e){var n=this,t=n.config,a=n.getContainer(),r=n.data(),d=a.header.items,a=(a.body.items,'[lay-closable="false"]'),o=(e=e===undefined?r.index:e,n.findHeaderItem(e)),l=(n.findBodyItem(e),o.index()),r=("false"!==r.thisHeaderItem.attr("lay-closable")&&("all"!==i&&i?e!==r.index&&n.change(o,!0):(e=d.filter(":gt("+r.index+")"+a).eq(0),o=p(d.filter(":lt("+r.index+")"+a).get().reverse()).eq(0),e[0]?n.change(e,!0):o[0]&&n.change(o,!0))),d.each(function(e){var t=p(this),a=t.attr("lay-id"),a=n.findBodyItem(a||e);"false"!==t.attr("lay-closable")&&("other"===i&&e!==l||"right"===i&&l");return t.html(e.title||"New Tab").attr("lay-id",e.id),this.appendClose(t,e),t},t.prototype.renderBodyItem=function(e){var t=this.config,t=p(e.bodyItem||t.bodyItem||'
          ');return t.html(e.content||"").attr("lay-id",e.id),t},t.prototype.appendClose=function(e,t){var a=this;a.config.closable&&(0==(t=t||{}).closable&&e.attr("lay-closable","false"),"false"===e.attr("lay-closable")||e.find("."+C.CONST.CLOSE)[0]||((t=p('')).on("click",function(){return a.close(p(this).parent()),!1}),e.append(t)))},t.prototype.renderClose=function(){var t=this,a=t.config;t.getContainer().header.items.each(function(){var e=p(this);a.closable?t.appendClose(e):e.find("."+C.CONST.CLOSE).remove()})},t.prototype.roll=function(e,i){var n=this,t=n.config,a=n.getContainer(),r=a.header.elem,d=a.header.items,a=r.prop("scrollWidth"),o=Math.ceil(r.outerWidth()),l=r.data("left")||0,s="scroll"===t.headerMode,c="layui-tabs-scroll",f="layui-tabs-bar",u=["layui-icon-prev","layui-icon-next"],m={elem:p('
          '),bar:p(['
          ','','',"
          "].join(""))};if("normal"!==t.headerMode){var h,y=r.parent("."+c);if(s||!s&&o=o-l)return r.css("left",-a).data("left",-a),!1}),l=r.data("left")||0,y.find("."+u[0])[l<0?"removeClass":"addClass"](C.CONST.CLASS_DISABLED),y.find("."+u[1])[0
          ')),n=(e.tree(a),i.elem=p(i.elem));if(n[0]){if(e.key=i.id||e.index,e.elem=a,e.elemNone=p('
          '+i.text.none+"
          "),n.html(e.elem),0==e.elem.find(".layui-tree-set").length)return e.elem.append(e.elemNone);i.showCheckbox&&e.renderForm("checkbox"),e.elem.find(".layui-tree-set").each(function(){var e=p(this);e.parent(".layui-tree-pack")[0]||e.addClass("layui-tree-setHide"),!e.next()[0]&&e.parents(".layui-tree-pack").eq(1).hasClass("layui-tree-lineExtend")&&e.addClass(T),e.next()[0]||e.parents(".layui-tree-set").eq(0).next()[0]||e.addClass(T)}),e.events()}},l.prototype.renderForm=function(e){i.render(e,"LAY-tree-"+this.index)},l.prototype.tree=function(r,e){var d=this,s=d.config,o=s.customName,e=e||s.data;layui.each(e,function(e,i){var a,n,t=i[o.children]&&0
          "),c=p(['
          ','
          ','
          ',s.showLine?t?'':'':'',s.showCheckbox?'':"",s.isJump&&i.href?''+(i[o.title]||i.label||s.text.defaultNodeName)+"":''+(i[o.title]||i.label||s.text.defaultNodeName)+"","
          ",s.edit?(a={add:'',update:'',del:''},n=['
          '],!0===s.edit&&(s.edit=["update","del"]),"object"==typeof s.edit?(layui.each(s.edit,function(e,i){n.push(a[i]||"")}),n.join("")+"
          "):void 0):"","
          "].join(""));t&&(c.append(l),d.tree(l,i[o.children])),r.append(c),c.prev("."+k)[0]&&c.prev().children(".layui-tree-pack").addClass("layui-tree-showLine"),t||c.parent(".layui-tree-pack").addClass("layui-tree-lineExtend"),d.spread(c,i),s.showCheckbox&&(i.checked&&d.checkids.push(i[o.id]),d.checkClick(c,i)),s.edit&&d.operate(c,i)})},l.prototype.spread=function(n,t){var l=this,c=l.config,e=n.children("."+b),i=e.children("."+g),a=i.find('input[same="layuiTreeCheck"]'),r=e.find("."+C),e=e.find("."+w),d=c.onlyIconControl?r:i,s="";d.on("click",function(e){var i=n.children("."+N),a=(d.children(".layui-icon")[0]?d:d.find(".layui-tree-icon")).children(".layui-icon");i[0]?n.hasClass(F)?(n.removeClass(F),i.slideUp(200),a.removeClass(x).addClass(v),l.updateFieldValue(t,"spread",!1)):(n.addClass(F),i.slideDown(200),a.addClass(x).removeClass(v),l.updateFieldValue(t,"spread",!0),c.accordion&&((i=n.siblings("."+k)).removeClass(F),i.children("."+N).slideUp(200),i.find(".layui-tree-icon").children(".layui-icon").removeClass(x).addClass(v))):s="normal"}),e.on("click",function(){p(this).hasClass(u)||(s=n.hasClass(F)?c.onlyIconControl?"open":"close":c.onlyIconControl?"close":"open",a[0]&&l.updateFieldValue(t,"checked",a.prop("checked")),c.click&&c.click({elem:n,state:s,data:t}))})},l.prototype.updateFieldValue=function(e,i,a){i in e&&(e[i]=a)},l.prototype.setCheckbox=function(e,i,a){var t,n=this,l=n.config.customName,c=a.prop("checked");a.prop("disabled")||("object"!=typeof i[l.children]&&!e.find("."+N)[0]||e.find("."+N).find('input[same="layuiTreeCheck"]').each(function(e){this.disabled||((e=i[l.children][e])&&n.updateFieldValue(e,"checked",c),n.updateFieldValue(this,"checked",c))}),(t=function(e){var i,a,n;e.parents("."+k)[0]&&(a=(e=e.parent("."+N)).parent(),n=e.prev().find('input[same="layuiTreeCheck"]'),c?n.prop("checked",c):(e.find('input[same="layuiTreeCheck"]').each(function(){this.checked&&(i=!0)}),i||n.prop("checked",!1)),t(a))})(e),n.renderForm("checkbox"))},l.prototype.checkClick=function(a,n){var t=this,l=t.config;a.children("."+b).children("."+g).on("click",'input[same="layuiTreeCheck"]+',function(e){layui.stope(e);var e=p(this).prev(),i=e.prop("checked");e.prop("disabled")||(t.setCheckbox(a,n,e),t.updateFieldValue(n,"checked",i),l.oncheck&&l.oncheck({elem:a,checked:i,data:n}))})},l.prototype.operate=function(r,d){var s=this,o=s.config,u=o.customName,e=r.children("."+b),h=e.children("."+g);e.children(".layui-tree-btnGroup").on("click",".layui-icon",function(e){layui.stope(e);var i,e=p(this).data("type"),n=r.children("."+N),t={data:d,type:e,elem:r};if("add"==e){n[0]||(o.showLine?(h.find("."+C).addClass("layui-tree-icon"),h.find("."+C).children(".layui-icon").addClass(v).removeClass("layui-icon-file")):h.find(".layui-tree-iconArrow").removeClass(m),r.append('
          '));var a,l=o.operate&&o.operate(t),c={};if(c[u.title]=o.text.defaultNodeName,c[u.id]=l,s.tree(r.children("."+N),[c]),o.showLine&&(n[0]?(n.hasClass(S)||n.addClass(S),r.find("."+N).each(function(){p(this).children("."+k).last().addClass(T)}),(n.children("."+k).last().prev().hasClass(T)?n.children("."+k).last().prev():n.children("."+k).last()).removeClass(T),!r.parent("."+N)[0]&&r.next()[0]&&n.children("."+k).last().removeClass(T)):(l=r.siblings("."+k),a=1,c=r.parent("."+N),layui.each(l,function(e,i){p(i).children("."+N)[0]||(a=0)}),(1==a?(l.children("."+N).addClass(L),l.children("."+N).children("."+k).removeClass(T),r.children("."+N).addClass(L),c.removeClass(S),c.children("."+k).last().children("."+N).children("."+k).last()):r.children("."+N).children("."+k)).addClass(T))),!o.showCheckbox)return;h.find('input[same="layuiTreeCheck"]')[0].checked&&(r.children("."+N).children("."+k).last().find('input[same="layuiTreeCheck"]')[0].checked=!0),s.renderForm("checkbox")}else"update"==e?(l=h.children("."+w).html(),h.children("."+w).html(""),h.append(''),h.children(".layui-tree-editInput").val(f.unescape(l)).focus(),i=function(e){var i=f.escape(e.val().trim())||o.text.defaultNodeName;e.remove(),h.children("."+w).html(i),t.data[u.title]=i,o.operate&&o.operate(t)},h.children(".layui-tree-editInput").blur(function(){i(p(this))}),h.children(".layui-tree-editInput").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),i(p(this)))})):y.confirm('\u786e\u8ba4\u5220\u9664\u8be5\u8282\u70b9 "'+(d[u.title]||"")+'" \u5417\uff1f',function(e){var l,a,i;o.operate&&o.operate(t),t.status="remove",y.close(e),r.prev("."+k)[0]||r.next("."+k)[0]||r.parent("."+N)[0]?(r.siblings("."+k).children("."+b)[0]?(o.showCheckbox&&(l=function(e){var i,a,n,t;e.parents("."+k)[0]&&(i=e.siblings("."+k).children("."+b),a=(e=e.parent("."+N).prev()).find('input[same="layuiTreeCheck"]')[0],n=1,(t=0)==a.checked)&&(i.each(function(e,i){i=p(i).find('input[same="layuiTreeCheck"]')[0];0!=i.checked||i.disabled||(n=0),i.disabled||(t=1)}),1==n)&&1==t&&(a.checked=!0,s.renderForm("checkbox"),l(e.parent("."+k)))})(r),o.showLine&&(e=r.siblings("."+k),a=1,i=r.parent("."+N),layui.each(e,function(e,i){p(i).children("."+N)[0]||(a=0)}),1==a?(n[0]||(i.removeClass(S),e.children("."+N).addClass(L),e.children("."+N).children("."+k).removeClass(T)),(r.next()[0]?i.children("."+k).last():r.prev()).children("."+N).children("."+k).last().addClass(T),r.next()[0]||r.parents("."+k)[1]||r.parents("."+k).eq(0).next()[0]||r.prev("."+k).addClass(T)):!r.next()[0]&&r.hasClass(T)&&r.prev().addClass(T))):(e=r.parent("."+N).prev(),o.showLine?(e.find("."+C).removeClass("layui-tree-icon"),e.find("."+C).children(".layui-icon").removeClass(x).addClass("layui-icon-file"),(i=e.parents("."+N).eq(0)).addClass(S),i.children("."+k).each(function(){p(this).children("."+N).children("."+k).last().addClass(T)})):e.find(".layui-tree-iconArrow").addClass(m),r.parents("."+k).eq(0).removeClass(F),r.parent("."+N).remove()),r.remove()):(r.remove(),s.elem.append(s.elemNone))})})},l.prototype.events=function(){var i=this,t=i.config;i.elem.find(".layui-tree-checkedFirst");i.setChecked(i.checkids),i.elem.find(".layui-tree-search").on("keyup",function(){var e=p(this),a=e.val(),e=e.nextAll(),n=[];e.find("."+w).each(function(){var i,e=p(this).parents("."+b);-1!=p(this).html().indexOf(a)&&(n.push(p(this).parent()),(i=function(e){e.addClass("layui-tree-searchShow"),e.parent("."+N)[0]&&i(e.parent("."+N).parent("."+k))})(e.parent("."+k)))}),e.find("."+b).each(function(){var e=p(this).parent("."+k);e.hasClass("layui-tree-searchShow")||e.addClass(m)}),0==e.find(".layui-tree-searchShow").length&&i.elem.append(i.elemNone),t.onsearch&&t.onsearch({elem:n})}),i.elem.find(".layui-tree-search").on("keydown",function(){p(this).nextAll().find("."+b).each(function(){p(this).parent("."+k).removeClass("layui-tree-searchShow "+m)}),p(".layui-tree-emptyText")[0]&&p(".layui-tree-emptyText").remove()})},l.prototype.getChecked=function(){var t=this,e=t.config,l=e.customName,i=[],a=[],c=(t.elem.find(".layui-form-checked").each(function(){i.push(p(this).prev()[0].value)}),function(e,n){layui.each(e,function(e,a){layui.each(i,function(e,i){if(a[l.id]==i)return t.updateFieldValue(a,"checked",!0),delete(i=p.extend({},a))[l.children],n.push(i),a[l.children]&&(i[l.children]=[],c(a[l.children],i[l.children])),!0})})});return c(p.extend({},e.data),a),a},l.prototype.setChecked=function(l){this.config;this.elem.find("."+k).each(function(e,i){var a=p(this).data("id"),n=p(i).children("."+b).find('input[same="layuiTreeCheck"]'),t=n.next();if("number"==typeof l){if(a.toString()==l.toString())return n[0].checked||t.click(),!1}else"object"==typeof l&&layui.each(l,function(e,i){if(i.toString()==a.toString()&&!n[0].checked)return t.click(),!0})})},n.that={},n.config={},t.reload=function(e,i){e=n.that[e];return e.reload(i),n.call(e)},t.getChecked=function(e){return n.that[e].getChecked()},t.setChecked=function(e,i){return n.that[e].setChecked(i)},t.render=function(e){e=new l(e);return n.call(e)},e(a,t)});layui.define(["laytpl","form"],function(e){"use strict";var d=layui.$,n=layui.laytpl,t=layui.form,a="transfer",i={config:{},index:layui[a]?layui[a].index+1e4:0,set:function(e){var t=this;return t.config=d.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,a,e,t)}},l=function(){var t=this,e=t.config,a=e.id||t.index;return l.that[a]=t,{config:l.config[a]=e,reload:function(e){t.reload.call(t,e)},getData:function(){return t.getData.call(t)}}},s="layui-hide",u="layui-btn-disabled",c="layui-none",r="layui-transfer-box",h="layui-transfer-header",o="layui-transfer-search",f="layui-transfer-data",y=function(e){return['
          ','
          ','","
          ","{{# if(d.data.showSearch){ }}",'","{{# } }}",'
            ',"
            "].join("")},p=['
            ',y({index:0,checkAllName:"layTransferLeftCheckAll"}),'
            ','",'","
            ",y({index:1,checkAllName:"layTransferRightCheckAll"}),"
            "].join(""),v=function(e){var t=this;t.index=++i.index,t.config=d.extend({},t.config,i.config,e),t.render()};v.prototype.config={title:["\u5217\u8868\u4e00","\u5217\u8868\u4e8c"],width:200,height:360,data:[],value:[],showSearch:!1,id:"",text:{none:"\u65e0\u6570\u636e",searchNone:"\u65e0\u5339\u914d\u6570\u636e"}},v.prototype.reload=function(e){var t=this;t.config=d.extend({},t.config,e),t.render()},v.prototype.render=function(){var e=this,t=e.config,a=e.elem=d(n(p,{open:"{{",close:"}}",tagStyle:"legacy"}).render({data:t,index:e.index})),i=t.elem=d(t.elem);i[0]&&(t.data=t.data||[],t.value=t.value||[],t.id="id"in t?t.id:elem.attr("id")||e.index,e.key=t.id,i.html(e.elem),e.layBox=e.elem.find("."+r),e.layHeader=e.elem.find("."+h),e.laySearch=e.elem.find("."+o),e.layData=a.find("."+f),e.layBtn=a.find(".layui-transfer-active .layui-btn"),e.layBox.css({width:t.width,height:t.height}),e.layData.css({height:(i=t.height-e.layHeader.outerHeight(),t.showSearch&&(i-=e.laySearch.outerHeight()),i-2)}),e.renderData(),e.events())},v.prototype.renderData=function(){var e=this,t=e.config,l=[{checkName:"layTransferLeftCheck",views:[]},{checkName:"layTransferRightCheck",views:[]}];e.parseData(function(a){var i=a.selected?1:0,n=["
          • ",'',"
          • "].join("");i?layui.each(t.value,function(e,t){t==a.value&&a.selected&&(l[i].views[e]=n)}):l[i].views.push(n),delete a.selected}),e.layData.eq(0).html(l[0].views.join("")),e.layData.eq(1).html(l[1].views.join("")),e.renderCheckBtn()},v.prototype.renderForm=function(e){t.render(e,"LAY-transfer-"+this.index)},v.prototype.renderCheckBtn=function(c){var r=this,o=r.config;c=c||{},r.layBox.each(function(e){var t=d(this),a=t.find("."+f),t=t.find("."+h).find('input[type="checkbox"]'),i=a.find('input[type="checkbox"]'),n=0,l=!1;i.each(function(){var e=d(this).data("hide");(this.checked||this.disabled||e)&&n++,this.checked&&!e&&(l=!0)}),t.prop("checked",l&&n===i.length),r.layBtn.eq(e)[l?"removeClass":"addClass"](u),c.stopNone||(i=a.children("li:not(."+s+")").length,r.noneView(a,i?"":o.text.none))}),r.renderForm("checkbox")},v.prototype.noneView=function(e,t){var a=d('

            '+(t||"")+"

            ");e.find("."+c)[0]&&e.find("."+c).remove(),t.replace(/\s/g,"")&&e.append(a)},v.prototype.setValue=function(){var e=this.config,t=[];return this.layBox.eq(1).find("."+f+' input[type="checkbox"]').each(function(){d(this).data("hide")||t.push(this.value)}),e.value=t,this},v.prototype.parseData=function(t){var i=this.config,n=[];return layui.each(i.data,function(e,a){a=("function"==typeof i.parseData?i.parseData(a):a)||a,n.push(a=d.extend({},a)),layui.each(i.value,function(e,t){t==a.value&&(a.selected=!0)}),t&&t(a)}),i.data=n,this},v.prototype.getData=function(e){var t=this.config,i=[];return this.setValue(),layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&i.push(t)})}),i},v.prototype.transfer=function(e,t){var a,i=this,n=i.config,l=i.layBox.eq(e),c=[],t=(t?((a=(t=t).find('input[type="checkbox"]'))[0].checked=!1,l.siblings("."+r).find("."+f).append(t.clone()),t.remove(),c.push(a[0].value),i.setValue()):l.each(function(e){d(this).find("."+f).children("li").each(function(){var e=d(this),t=e.find('input[type="checkbox"]'),a=t.data("hide");t[0].checked&&!a&&(t[0].checked=!1,l.siblings("."+r).find("."+f).append(e.clone()),e.remove(),c.push(t[0].value)),i.setValue()})}),i.renderCheckBtn(),l.siblings("."+r).find("."+o+" input"));""!==t.val()&&t.trigger("keyup"),n.onchange&&n.onchange(i.getData(c),e)},v.prototype.events=function(){var n=this,l=n.config;n.elem.on("click",'input[lay-filter="layTransferCheckbox"]+',function(){var e=d(this).prev(),t=e[0].checked,a=e.parents("."+r).eq(0).find("."+f);e[0].disabled||("all"===e.attr("lay-type")&&a.find('input[type="checkbox"]').each(function(){this.disabled||(this.checked=t)}),setTimeout(function(){n.renderCheckBtn({stopNone:!0})},0))}),n.elem.on("dblclick","."+f+">li",function(e){var t=d(this),a=t.children('input[type="checkbox"]'),i=t.parent().parent().data("index");a[0].disabled||!1!==("function"==typeof l.dblclick?l.dblclick({elem:t,data:n.getData([a[0].value])[0],index:i}):null)&&n.transfer(i,t)}),n.layBtn.on("click",function(){var e=d(this),t=e.data("index");e.hasClass(u)||n.transfer(t)}),n.laySearch.find("input").on("keyup",function(){var i=this.value,e=d(this).parents("."+o).eq(0).siblings("."+f),t=e.children("li"),t=(t.each(function(){var e=d(this),t=e.find('input[type="checkbox"]'),a=t[0].title,a=("cs"!==l.showSearch&&(a=a.toLowerCase(),i=i.toLowerCase()),-1!==a.indexOf(i));e[a?"removeClass":"addClass"](s),t.data("hide",!a)}),n.renderCheckBtn(),t.length===e.children("li."+s).length);n.noneView(e,t?l.text.searchNone:"")})},l.that={},l.config={},i.reload=function(e,t){e=l.that[e];return e.reload(t),l.call(e)},i.getData=function(e){return l.that[e].getData()},i.render=function(e){e=new v(e);return l.call(e)},e(a,i)});layui.define(["jquery","lay"],function(e){"use strict";var o=layui.$,l=layui.lay,t=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=o.extend({},n.config,e),n},on:function(e,n){return layui.onevent.call(this,r,e,n)}}),r="carousel",s="layui-this",u="layui-carousel-left",c="layui-carousel-right",m="layui-carousel-prev",h="layui-carousel-next",a="layui-carousel-arrow",d="layui-carousel-ind",n=function(e){var n=this;n.config=o.extend({},n.config,t.config,e),n.render()};n.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},n.prototype.render=function(){var e=this,n=e.config,i=o(n.elem);if(1*[carousel-item]>*"),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(s),e.indicator(),e.arrow(),e.autoplay(),1=this.elemItem.length?0:e},n.prototype.addIndex=function(e){var n=this.config;n.index=n.index+(e=e||1),n.index>=this.elemItem.length&&(n.index=0)},n.prototype.subIndex=function(e){var n=this.config;n.index=n.index-(e=e||1),n.index<0&&(n.index=this.elemItem.length-1)},n.prototype.autoplay=function(){var e=this,n=e.config,i=e.elemItem.length;n.autoplay&&(clearInterval(e.timer),1',''].join(""));e.elem.attr("lay-arrow",e.arrow),e.elem.find("."+a)[0]&&e.elem.find("."+a).remove(),1i.index?n.slide("add",e-i.index):e
              ',(n=[],layui.each(e.elemItem,function(e){n.push("")}),n.join("")),"
            "].join(""));i.elem.attr("lay-indicator",i.indicator),i.elem.find("."+d)[0]&&i.elem.find("."+d).remove(),1t[a?"height":"width"]()/3)&&o.slide(0a.length&&(a.value=a.length),parseInt(a.value)===a.value||a.half||(a.value=Math.ceil(a.value)-a.value<.5?Math.ceil(a.value):Math.floor(a.value)),'
              "),i=1;i<=a.length;i++){var n='
            • ";a.half&&parseInt(a.value)!==a.value&&i==Math.ceil(a.value)?t=t+'
            • ":t+=n}t+="
            ",a.text&&(t+=''+a.value+"");var s=a.elem,o=s.next("."+c.ELEM);o[0]&&o.remove(),e.elemTemplate=u(t),a.span=e.elemTemplate.next("span"),a.setText&&a.setText(a.value),s.html(e.elemTemplate),s.addClass("layui-inline"),a.readonly||e.action()},extendsInstance:function(){var a=this,l=a.config;return{setvalue:function(e){l.value=e,a.render()}}}}),c=l.CONST;l.Class.prototype.action=function(){var n=this.config,t=this.elemTemplate,i=t.find("i").width(),l=t.children("li");l.each(function(e){var a=e+1,l=u(this);l.on("click",function(e){n.value=a,n.half&&e.pageX-u(this).offset().left<=i/2&&(n.value=n.value-.5),n.text&&t.next("span").text(n.value),n.choose&&n.choose(n.value),n.setText&&n.setText(n.value)}),l.on("mousemove",function(e){t.find("i").each(function(){u(this).addClass(c.ICON_RATE).removeClass(c.ICON_SOLID_HALF)}),t.find("i:lt("+a+")").each(function(){u(this).addClass(c.ICON_RATE_SOLID).removeClass(c.ICON_HALF_RATE)}),n.half&&e.pageX-u(this).offset().left<=i/2&&l.children("i").addClass(c.ICON_RATE_HALF).removeClass(c.ICON_RATE_SOLID)}),l.on("mouseleave",function(){t.find("i").each(function(){u(this).addClass(c.ICON_RATE).removeClass(c.ICON_SOLID_HALF)}),t.find("i:lt("+Math.floor(n.value)+")").each(function(){u(this).addClass(c.ICON_RATE_SOLID).removeClass(c.ICON_HALF_RATE)}),n.half&&parseInt(n.value)!==n.value&&t.children("li:eq("+Math.floor(n.value)+")").children("i").addClass(c.ICON_RATE_HALF).removeClass(c.ICON_SOLID_RATE)})}),a.touchSwipe(t,{onTouchMove:function(e,a){var i;Date.now()-a.timeStart<=200||(a=e.touches[0].pageX,e=t.width()/n.length,a=(a-t.offset().left)/e,(i=(i=(e=a%1)<=.5&&n.half?.5+(a-e):Math.ceil(a))>n.length?n.length:i)<0&&(i=0),l.each(function(e){var a=u(this).children("i"),l=Math.ceil(i)-e==1,t=Math.ceil(i)>e,e=i-e==.5;t?(a.addClass(c.ICON_RATE_SOLID).removeClass(c.ICON_HALF_RATE),n.half&&e&&a.addClass(c.ICON_RATE_HALF).removeClass(c.ICON_RATE_SOLID)):a.addClass(c.ICON_RATE).removeClass(c.ICON_SOLID_HALF),a.toggleClass("layui-rate-hover",l)}),n.value=i,n.text&&t.next("span").text(n.value),n.setText&&n.setText(n.value))},onTouchEnd:function(e,a){Date.now()-a.timeStart<=200||(t.find("i").removeClass("layui-rate-hover"),n.choose&&n.choose(n.value),n.setText&&n.setText(n.value))}})},e(c.MOD_NAME,l)});layui.define("jquery",function(o){"use strict";var w=layui.$,l=function(o){};l.prototype.load=function(o){var i,n,r,l,c,m,e,t,a,f,s,u,p,d,y,g=this,h=0,v=w((o=o||{}).elem);if(v[0])return c=w(o.scrollElem||document),m="mb"in o?o.mb:50,e=!("isAuto"in o)||o.isAuto,t=o.moreText||"\u52a0\u8f7d\u66f4\u591a",a=o.end||"\u6ca1\u6709\u66f4\u591a\u4e86",f="top"===(o.direction||"bottom"),g._cleanup(v,c),s=o.scrollElem&&o.scrollElem!==document,p=w('"),v.find(".layui-flow-more")[0]||v[f?"prepend":"append"](p),d=function(o,l){var e=s?c.prop("scrollHeight"):document.documentElement.scrollHeight,t=c.scrollTop();o=w(o),p[f?"after":"before"](o),(l=0==l||null)?p.html(a):p.find("a").html(u),n=l,i=null,r&&r(),f&&(o=s?c.prop("scrollHeight"):document.documentElement.scrollHeight,1===h?c.scrollTop(o):1'),"function"==typeof o.done&&o.done(++h,d)})(),p.find("a").on("click.flow",function(){w(this);n||i||y()}),o.isLazyimg&&(r=g.lazyimg({elem:o.elem+" img",scrollElem:o.scrollElem,direction:o.direction})),e&&c.on("scroll.flow",function(){var e=w(this),t=e.scrollTop();l&&clearTimeout(l),!n&&v.width()&&(l=setTimeout(function(){var o=(s?e:w(window)).height(),l=s?e.prop("scrollHeight"):document.documentElement.scrollHeight;(f?t<=m:l-t-o<=m)&&!i&&y()},100))}),g},l.prototype.lazyimg=function(o){var l,m=this,a=0,f=w((o=o||{}).scrollElem||document),s=o.elem||"img",n="top"===(o.direction||"bottom"),u=o.scrollElem&&o.scrollElem!==document,p=function(l,o){var e,t=f.scrollTop(),o=t+o,i=u?l.offset().top-f.offset().top+t:l.offset().top;(n?i+l.height():i)>=t&&i<=o&&l.attr("lay-src")&&(e=l.attr("lay-src"),layui.img(e,function(){var o=m.lazyimg.elem.eq(a);l.attr("src",e).removeAttr("lay-src"),o[0]&&r(o),a++},function(){m.lazyimg.elem.eq(a);l.removeAttr("lay-src")}))},r=function(o,l){var e=(u?l||f:w(window)).height(),t=f.scrollTop(),i=t+e;if(m.lazyimg.elem=w(s),o)p(o,e);else for(var n=0;n"),preview:"Preview"},wordWrap:!0,lang:"text",highlighter:!1,langMarker:!1},R=layui.code?layui.code.index+1e4:0,j=function(e){return String(e).replace(/\s+$/,"").replace(/^\n|\n$/,"")};e("code",function(l,e){var o,i,t,a,n,d,c,s,r,u,y,p,E,f,h,v,m,L,_,M,C,g={config:l=x.extend(!0,{},T,l),reload:function(e){layui.code(this.updateOptions(e))},updateOptions:function(e){return delete(e=e||{}).elem,x.extend(!0,l,e)},reloadCode:function(e){layui.code(this.updateOptions(e),"reloadCode")}},w=x(l.elem);return 1',l.ln?['
            ',D.digit(t+1)+".","
            "].join(""):"",'
            ',e||" ","
            ","
            "].join("")})}},a=l.code,n=function(e){return"function"==typeof l.codeParse?l.codeParse(e,l):e},"reloadCode"===e?o.children(".layui-code-wrap").html(w(n(a)).html):(d=layui.code.index=++R,o.attr("lay-code-index",d),(M=A.CDDE_DATA_CLASS in o.data())&&o.attr("class",o.data(A.CDDE_DATA_CLASS)||""),M||o.data(A.CDDE_DATA_CLASS,o.attr("class")),c={copy:{className:"file-b",title:["\u590d\u5236\u4ee3\u7801"],event:function(e){var t=D.unescape(n(l.code)),a="function"==typeof l.onCopy;lay.clipboard.writeText({text:t,done:function(){if(a&&!1===l.onCopy(t,!0))return;W.msg("\u5df2\u590d\u5236",{icon:1})},error:function(){if(a&&!1===l.onCopy(t,!1))return;W.msg("\u590d\u5236\u5931\u8d25",{icon:2})}})}}},function b(){var e=o.parent("."+A.ELEM_PREVIEW),t=e.children("."+A.ELEM_TAB),a=e.children("."+A.ELEM_ITEM+"-preview");return t.remove(),a.remove(),e[0]&&o.unwrap(),b}(),l.preview&&(M="LAY-CODE-DF-"+d,f=l.layout||["code","preview"],s="iframe"===l.preview,E=x('
            '),C=x('
            '),r=x('
            '),_=x('
            '),u=x('
            '),l.id&&E.attr("id",l.id),E.addClass(l.className),C.attr("lay-filter",M),layui.each(f,function(e,t){var a=x('
          • ');0===e&&a.addClass("layui-this"),a.html(l.text[t]),r.append(a)}),x.extend(c,{full:{className:"screen-full",title:["\u6700\u5927\u5316\u663e\u793a","\u8fd8\u539f\u663e\u793a"],event:function(e){var e=e.elem,t=e.closest("."+A.ELEM_PREVIEW),a="layui-icon-"+this.className,i="layui-icon-screen-restore",l=this.title,o=x("html,body"),n="layui-scrollbar-hide";e.hasClass(a)?(t.addClass(A.ELEM_FULL),e.removeClass(a).addClass(i),e.attr("title",l[1]),o.addClass(n)):(t.removeClass(A.ELEM_FULL),e.removeClass(i).addClass(a),e.attr("title",l[0]),o.removeClass(n))}},window:{className:"release",title:["\u5728\u65b0\u7a97\u53e3\u9884\u89c8"],event:function(e){D.openWin({content:n(l.code)})}}}),l.copy&&("array"===layui.type(l.tools)?-1===l.tools.indexOf("copy")&&l.tools.unshift("copy"):l.tools=["copy"]),u.on("click",">i",function(){var e=x(this),t=e.data("type"),e={elem:e,type:t,options:l,rawCode:l.code,finalCode:D.unescape(n(l.code))};c[t]&&"function"==typeof c[t].event&&c[t].event(e),"function"==typeof l.toolsEvent&&l.toolsEvent(e)}),l.addTools&&l.tools&&(l.tools=[].concat(l.tools,l.addTools)),layui.each(l.tools,function(e,t){var a="object"==typeof t,i=a?t:c[t]||{className:t,title:[t]},l=i.className||i.type,o=i.title||[""],a=a?i.type||l:t;a&&(c[a]||((t={})[a]=i,x.extend(c,t)),u.append(''))}),o.addClass(A.ELEM_ITEM).wrap(E),C.append(r),l.tools&&C.append(u),o.before(C),s&&_.html(''),y=function(e){var t=e.children("iframe")[0];s&&t?t.srcdoc=n(l.code):e.html(l.code),setTimeout(function(){"function"==typeof l.done&&l.done({container:e,options:l,render:function(){N.render(e.find(".layui-form")),S.render(),I.render({elem:["."+A.ELEM_PREVIEW,".layui-tabs"].join(" ")})}})},3)},"preview"===f[0]?(_.addClass(A.ELEM_SHOW),o.before(_),y(_)):o.addClass(A.ELEM_SHOW).after(_),l.previewStyle=[l.style,l.previewStyle].join(""),_.attr("style",l.previewStyle),S.on("tab("+M+")",function(e){var t=x(this),a=x(e.elem).closest("."+A.ELEM_PREVIEW).find("."+A.ELEM_ITEM),e=a.eq(e.index);a.removeClass(A.ELEM_SHOW),e.addClass(A.ELEM_SHOW),"preview"===t.attr("lay-id")&&y(e),L()})),p=x(''),o.addClass((E=["layui-code-view layui-border-box"],l.wordWrap||E.push("layui-code-nowrap"),E.join(" "))),(C=l.theme||l.skin)&&(o.removeClass("layui-code-theme-dark layui-code-theme-light"),o.addClass("layui-code-theme-"+C)),l.highlighter&&o.addClass([l.highlighter,"language-"+l.lang,"layui-code-hl"].join(" ")),f=w(l.encode?D.escape(n(a)):a),h=f.lines,o.html(p.html(f.html)),l.ln&&o.append('
            '),l.height&&p.css("max-height",l.height),l.codeStyle=[l.style,l.codeStyle].join(""),l.codeStyle&&p.attr("style",function(e,t){return(t||"")+l.codeStyle}),v=[{selector:">.layui-code-wrap>.layui-code-line{}",setValue:function(e,t){e.style["padding-left"]=t+"px"}},{selector:">.layui-code-wrap>.layui-code-line>.layui-code-line-number{}",setValue:function(e,t){e.style.width=t+"px"}},{selector:">.layui-code-ln-side{}",setValue:function(e,t){e.style.width=t+"px"}}],m=lay.style({target:o[0],id:"DF-code-"+d,text:x.map(x.map(v,function(e){return e.selector}),function(e,t){return['.layui-code-view[lay-code-index="'+d+'"]',e].join(" ")}).join("")}),L=function b(){var e,i;return l.ln&&(e=Math.floor(h.length/100),i=p.children("."+A.ELEM_LINE).last().children("."+A.ELEM_LINE_NUM).outerWidth(),o.addClass(A.ELEM_LN_MODE),e)&&A.LINE_RAW_WIDTH
          • ')).html(l.title||l.text.code),o.prepend(_)),M=x('
            '),l.copy&&!l.preview&&((C=x(['','',""].join(""))).on("click",function(){c.copy.event()}),M.append(C)),l.langMarker&&M.append(''+l.lang+""),l.about&&M.append(l.about),o.append(M),l.preview||setTimeout(function(){"function"==typeof l.done&&l.done({})},3),l.elem.length===1+d&&"function"==typeof l.allDone&&l.allDone())),g})}),layui["layui.all"]||layui.addcss("modules/code.css?v=6","skincodecss"); \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/layui.css b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/layui.css new file mode 100644 index 0000000..7d0659d --- /dev/null +++ b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/layui.css @@ -0,0 +1,5787 @@ +.layui-inline, img { + display: inline-block; + vertical-align: middle +} + +h1, h2, h3, h4, h5, h6 { + font-weight: 400 +} + +a, body { + color: #333 +} + +.layui-edge, .layui-header, .layui-inline, .layui-main { + position: relative +} + +.layui-edge, hr { + height: 0; + overflow: hidden +} + +.layui-layout-body, .layui-side, .layui-side-scroll { + overflow-x: hidden +} + +.layui-btn, .layui-edge, .layui-inline, img { + vertical-align: middle +} + +.layui-btn, .layui-disabled, .layui-icon, .layui-unselect { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none +} + +.layui-elip, .layui-form-checkbox span, .layui-form-pane .layui-form-label { + text-overflow: ellipsis; + white-space: nowrap +} + +.layui-edge, .layui-elip, hr { + overflow: hidden +} + +blockquote, body, button, dd, div, dl, dt, form, h1, h2, h3, h4, h5, h6, input, li, ol, p, pre, td, textarea, th, ul { + margin: 0; + padding: 0; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0) +} + +a:active, a:hover { + outline: 0 +} + +img { + border: none +} + +li { + list-style: none +} + +table { + border-collapse: collapse; + border-spacing: 0 +} + +h4, h5, h6 { + font-size: 100% +} + +button, input, optgroup, option, select, textarea { + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + outline: 0 +} + +pre { + white-space: pre-wrap; + white-space: -moz-pre-wrap; + white-space: -pre-wrap; + white-space: -o-pre-wrap; + word-wrap: break-word +} + +body { + line-height: 1.6; + color: rgba(0, 0, 0, .85); + font: 14px Helvetica Neue, Helvetica, PingFang SC, Tahoma, Arial, sans-serif +} + +hr { + line-height: 0; + margin: 10px 0; + padding: 0; + border: none !important; + border-bottom: 1px solid #eee !important; + clear: both; + background: 0 0 +} + +a { + text-decoration: none +} + +a:hover { + color: #777 +} + +a cite { + font-style: normal; + *cursor: pointer +} + +.layui-border-box, .layui-border-box * { + box-sizing: border-box +} + +.layui-box, .layui-box * { + box-sizing: content-box +} + +.layui-clear { + clear: both; + *zoom: 1 +} + +.layui-clear:after { + content: '\20'; + clear: both; + *zoom: 1; + display: block; + height: 0 +} + +.layui-inline { + *display: inline; + *zoom: 1 +} + +.layui-edge { + display: inline-block; + width: 0; + border-width: 6px; + border-style: dashed; + border-color: transparent +} + +.layui-edge-top { + top: -4px; + border-bottom-color: #999; + border-bottom-style: solid +} + +.layui-edge-right { + border-left-color: #999; + border-left-style: solid +} + +.layui-edge-bottom { + top: 2px; + border-top-color: #999; + border-top-style: solid +} + +.layui-edge-left { + border-right-color: #999; + border-right-style: solid +} + +.layui-disabled, .layui-disabled:hover { + color: #d2d2d2 !important; + cursor: not-allowed !important +} + +.layui-circle { + border-radius: 100% +} + +.layui-show { + display: block !important +} + +.layui-hide { + display: none !important +} + +.layui-show-v { + visibility: visible !important +} + +.layui-hide-v { + visibility: hidden !important +} + +@font-face { + font-family: layui-icon; + src: url(../font/iconfont.eot?v=256); + src: url(../font/iconfont.eot?v=256#iefix) format('embedded-opentype'), url(../font/iconfont.woff2?v=256) format('woff2'), url(../font/iconfont.woff?v=256) format('woff'), url(../font/iconfont.ttf?v=256) format('truetype'), url(../font/iconfont.svg?v=256#layui-icon) format('svg') +} + +.layui-icon { + font-family: layui-icon !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale +} + +.layui-icon-reply-fill:before { + content: "\e611" +} + +.layui-icon-set-fill:before { + content: "\e614" +} + +.layui-icon-menu-fill:before { + content: "\e60f" +} + +.layui-icon-search:before { + content: "\e615" +} + +.layui-icon-share:before { + content: "\e641" +} + +.layui-icon-set-sm:before { + content: "\e620" +} + +.layui-icon-engine:before { + content: "\e628" +} + +.layui-icon-close:before { + content: "\1006" +} + +.layui-icon-close-fill:before { + content: "\1007" +} + +.layui-icon-chart-screen:before { + content: "\e629" +} + +.layui-icon-star:before { + content: "\e600" +} + +.layui-icon-circle-dot:before { + content: "\e617" +} + +.layui-icon-chat:before { + content: "\e606" +} + +.layui-icon-release:before { + content: "\e609" +} + +.layui-icon-list:before { + content: "\e60a" +} + +.layui-icon-chart:before { + content: "\e62c" +} + +.layui-icon-ok-circle:before { + content: "\1005" +} + +.layui-icon-layim-theme:before { + content: "\e61b" +} + +.layui-icon-table:before { + content: "\e62d" +} + +.layui-icon-right:before { + content: "\e602" +} + +.layui-icon-left:before { + content: "\e603" +} + +.layui-icon-cart-simple:before { + content: "\e698" +} + +.layui-icon-face-cry:before { + content: "\e69c" +} + +.layui-icon-face-smile:before { + content: "\e6af" +} + +.layui-icon-survey:before { + content: "\e6b2" +} + +.layui-icon-tree:before { + content: "\e62e" +} + +.layui-icon-ie:before { + content: "\e7bb" +} + +.layui-icon-upload-circle:before { + content: "\e62f" +} + +.layui-icon-add-circle:before { + content: "\e61f" +} + +.layui-icon-download-circle:before { + content: "\e601" +} + +.layui-icon-templeate-1:before { + content: "\e630" +} + +.layui-icon-util:before { + content: "\e631" +} + +.layui-icon-face-surprised:before { + content: "\e664" +} + +.layui-icon-edit:before { + content: "\e642" +} + +.layui-icon-speaker:before { + content: "\e645" +} + +.layui-icon-down:before { + content: "\e61a" +} + +.layui-icon-file:before { + content: "\e621" +} + +.layui-icon-layouts:before { + content: "\e632" +} + +.layui-icon-rate-half:before { + content: "\e6c9" +} + +.layui-icon-add-circle-fine:before { + content: "\e608" +} + +.layui-icon-prev-circle:before { + content: "\e633" +} + +.layui-icon-read:before { + content: "\e705" +} + +.layui-icon-404:before { + content: "\e61c" +} + +.layui-icon-carousel:before { + content: "\e634" +} + +.layui-icon-help:before { + content: "\e607" +} + +.layui-icon-code-circle:before { + content: "\e635" +} + +.layui-icon-windows:before { + content: "\e67f" +} + +.layui-icon-water:before { + content: "\e636" +} + +.layui-icon-username:before { + content: "\e66f" +} + +.layui-icon-find-fill:before { + content: "\e670" +} + +.layui-icon-about:before { + content: "\e60b" +} + +.layui-icon-location:before { + content: "\e715" +} + +.layui-icon-up:before { + content: "\e619" +} + +.layui-icon-pause:before { + content: "\e651" +} + +.layui-icon-date:before { + content: "\e637" +} + +.layui-icon-layim-uploadfile:before { + content: "\e61d" +} + +.layui-icon-delete:before { + content: "\e640" +} + +.layui-icon-play:before { + content: "\e652" +} + +.layui-icon-top:before { + content: "\e604" +} + +.layui-icon-firefox:before { + content: "\e686" +} + +.layui-icon-friends:before { + content: "\e612" +} + +.layui-icon-refresh-3:before { + content: "\e9aa" +} + +.layui-icon-ok:before { + content: "\e605" +} + +.layui-icon-layer:before { + content: "\e638" +} + +.layui-icon-face-smile-fine:before { + content: "\e60c" +} + +.layui-icon-dollar:before { + content: "\e659" +} + +.layui-icon-group:before { + content: "\e613" +} + +.layui-icon-layim-download:before { + content: "\e61e" +} + +.layui-icon-picture-fine:before { + content: "\e60d" +} + +.layui-icon-link:before { + content: "\e64c" +} + +.layui-icon-diamond:before { + content: "\e735" +} + +.layui-icon-log:before { + content: "\e60e" +} + +.layui-icon-key:before { + content: "\e683" +} + +.layui-icon-rate-solid:before { + content: "\e67a" +} + +.layui-icon-fonts-del:before { + content: "\e64f" +} + +.layui-icon-unlink:before { + content: "\e64d" +} + +.layui-icon-fonts-clear:before { + content: "\e639" +} + +.layui-icon-triangle-r:before { + content: "\e623" +} + +.layui-icon-circle:before { + content: "\e63f" +} + +.layui-icon-radio:before { + content: "\e643" +} + +.layui-icon-align-center:before { + content: "\e647" +} + +.layui-icon-align-right:before { + content: "\e648" +} + +.layui-icon-align-left:before { + content: "\e649" +} + +.layui-icon-loading-1:before { + content: "\e63e" +} + +.layui-icon-return:before { + content: "\e65c" +} + +.layui-icon-fonts-strong:before { + content: "\e62b" +} + +.layui-icon-upload:before { + content: "\e67c" +} + +.layui-icon-dialogue:before { + content: "\e63a" +} + +.layui-icon-video:before { + content: "\e6ed" +} + +.layui-icon-headset:before { + content: "\e6fc" +} + +.layui-icon-cellphone-fine:before { + content: "\e63b" +} + +.layui-icon-add-1:before { + content: "\e654" +} + +.layui-icon-face-smile-b:before { + content: "\e650" +} + +.layui-icon-fonts-html:before { + content: "\e64b" +} + +.layui-icon-screen-full:before { + content: "\e622" +} + +.layui-icon-form:before { + content: "\e63c" +} + +.layui-icon-cart:before { + content: "\e657" +} + +.layui-icon-camera-fill:before { + content: "\e65d" +} + +.layui-icon-tabs:before { + content: "\e62a" +} + +.layui-icon-heart-fill:before { + content: "\e68f" +} + +.layui-icon-fonts-code:before { + content: "\e64e" +} + +.layui-icon-ios:before { + content: "\e680" +} + +.layui-icon-at:before { + content: "\e687" +} + +.layui-icon-fire:before { + content: "\e756" +} + +.layui-icon-set:before { + content: "\e716" +} + +.layui-icon-fonts-u:before { + content: "\e646" +} + +.layui-icon-triangle-d:before { + content: "\e625" +} + +.layui-icon-tips:before { + content: "\e702" +} + +.layui-icon-picture:before { + content: "\e64a" +} + +.layui-icon-more-vertical:before { + content: "\e671" +} + +.layui-icon-bluetooth:before { + content: "\e689" +} + +.layui-icon-flag:before { + content: "\e66c" +} + +.layui-icon-loading:before { + content: "\e63d" +} + +.layui-icon-fonts-i:before { + content: "\e644" +} + +.layui-icon-refresh-1:before { + content: "\e666" +} + +.layui-icon-rmb:before { + content: "\e65e" +} + +.layui-icon-addition:before { + content: "\e624" +} + +.layui-icon-home:before { + content: "\e68e" +} + +.layui-icon-time:before { + content: "\e68d" +} + +.layui-icon-user:before { + content: "\e770" +} + +.layui-icon-notice:before { + content: "\e667" +} + +.layui-icon-chrome:before { + content: "\e68a" +} + +.layui-icon-edge:before { + content: "\e68b" +} + +.layui-icon-login-weibo:before { + content: "\e675" +} + +.layui-icon-voice:before { + content: "\e688" +} + +.layui-icon-upload-drag:before { + content: "\e681" +} + +.layui-icon-login-qq:before { + content: "\e676" +} + +.layui-icon-snowflake:before { + content: "\e6b1" +} + +.layui-icon-heart:before { + content: "\e68c" +} + +.layui-icon-logout:before { + content: "\e682" +} + +.layui-icon-file-b:before { + content: "\e655" +} + +.layui-icon-template:before { + content: "\e663" +} + +.layui-icon-transfer:before { + content: "\e691" +} + +.layui-icon-auz:before { + content: "\e672" +} + +.layui-icon-console:before { + content: "\e665" +} + +.layui-icon-app:before { + content: "\e653" +} + +.layui-icon-prev:before { + content: "\e65a" +} + +.layui-icon-website:before { + content: "\e7ae" +} + +.layui-icon-next:before { + content: "\e65b" +} + +.layui-icon-component:before { + content: "\e857" +} + +.layui-icon-android:before { + content: "\e684" +} + +.layui-icon-more:before { + content: "\e65f" +} + +.layui-icon-login-wechat:before { + content: "\e677" +} + +.layui-icon-shrink-right:before { + content: "\e668" +} + +.layui-icon-spread-left:before { + content: "\e66b" +} + +.layui-icon-camera:before { + content: "\e660" +} + +.layui-icon-note:before { + content: "\e66e" +} + +.layui-icon-refresh:before { + content: "\e669" +} + +.layui-icon-female:before { + content: "\e661" +} + +.layui-icon-male:before { + content: "\e662" +} + +.layui-icon-screen-restore:before { + content: "\e758" +} + +.layui-icon-password:before { + content: "\e673" +} + +.layui-icon-senior:before { + content: "\e674" +} + +.layui-icon-theme:before { + content: "\e66a" +} + +.layui-icon-tread:before { + content: "\e6c5" +} + +.layui-icon-praise:before { + content: "\e6c6" +} + +.layui-icon-star-fill:before { + content: "\e658" +} + +.layui-icon-rate:before { + content: "\e67b" +} + +.layui-icon-template-1:before { + content: "\e656" +} + +.layui-icon-vercode:before { + content: "\e679" +} + +.layui-icon-service:before { + content: "\e626" +} + +.layui-icon-cellphone:before { + content: "\e678" +} + +.layui-icon-print:before { + content: "\e66d" +} + +.layui-icon-cols:before { + content: "\e610" +} + +.layui-icon-wifi:before { + content: "\e7e0" +} + +.layui-icon-export:before { + content: "\e67d" +} + +.layui-icon-rss:before { + content: "\e808" +} + +.layui-icon-slider:before { + content: "\e714" +} + +.layui-icon-email:before { + content: "\e618" +} + +.layui-icon-subtraction:before { + content: "\e67e" +} + +.layui-icon-mike:before { + content: "\e6dc" +} + +.layui-icon-light:before { + content: "\e748" +} + +.layui-icon-gift:before { + content: "\e627" +} + +.layui-icon-mute:before { + content: "\e685" +} + +.layui-icon-reduce-circle:before { + content: "\e616" +} + +.layui-icon-music:before { + content: "\e690" +} + +.layui-main { + width: 1140px; + margin: 0 auto +} + +.layui-header { + z-index: 1000; + height: 60px +} + +.layui-header a:hover { + transition: all .5s; + -webkit-transition: all .5s +} + +.layui-side { + position: fixed; + left: 0; + top: 0; + bottom: 0; + z-index: 999; + width: 200px +} + +.layui-side-scroll { + position: relative; + width: 220px; + height: 100% +} + +.layui-body { + position: relative; + left: 200px; + right: 0; + top: 0; + bottom: 0; + z-index: 900; + width: auto; + box-sizing: border-box +} + +.layui-layout-admin .layui-header { + position: fixed; + top: 0; + left: 0; + right: 0; + background-color: #23262E +} + +.layui-layout-admin .layui-side { + top: 60px; + width: 200px; + overflow-x: hidden +} + +.layui-layout-admin .layui-body { + position: absolute; + top: 60px; + padding-bottom: 10px +} + +.layui-layout-admin .layui-main { + width: auto; + margin: 0 15px +} + +.layui-layout-admin .layui-footer { + position: fixed; + left: 200px; + right: 0; + bottom: 0; + z-index: 990; + height: 44px; + line-height: 44px; + padding: 0 15px; + box-shadow: -1px 0 4px rgb(0 0 0 / 12%); + background-color: #FAFAFA +} + +.layui-layout-admin .layui-logo { + position: absolute; + left: 0; + top: 0; + width: 200px; + height: 100%; + line-height: 60px; + text-align: center; + color: #009688; + font-size: 16px +} + +.layui-layout-admin .layui-header .layui-nav { + background: 0 0 +} + +.layui-layout-left { + position: absolute !important; + left: 200px; + top: 0 +} + +.layui-layout-right { + position: absolute !important; + right: 0; + top: 0 +} + +.layui-container { + position: relative; + margin: 0 auto; + padding: 0 15px; + box-sizing: border-box +} + +.layui-fluid { + position: relative; + margin: 0 auto; + padding: 0 15px +} + +.layui-row:after, .layui-row:before { + content: ""; + display: block; + clear: both +} + +.layui-col-lg1, .layui-col-lg10, .layui-col-lg11, .layui-col-lg12, .layui-col-lg2, .layui-col-lg3, .layui-col-lg4, .layui-col-lg5, .layui-col-lg6, .layui-col-lg7, .layui-col-lg8, .layui-col-lg9, .layui-col-md1, .layui-col-md10, .layui-col-md11, .layui-col-md12, .layui-col-md2, .layui-col-md3, .layui-col-md4, .layui-col-md5, .layui-col-md6, .layui-col-md7, .layui-col-md8, .layui-col-md9, .layui-col-sm1, .layui-col-sm10, .layui-col-sm11, .layui-col-sm12, .layui-col-sm2, .layui-col-sm3, .layui-col-sm4, .layui-col-sm5, .layui-col-sm6, .layui-col-sm7, .layui-col-sm8, .layui-col-sm9, .layui-col-xs1, .layui-col-xs10, .layui-col-xs11, .layui-col-xs12, .layui-col-xs2, .layui-col-xs3, .layui-col-xs4, .layui-col-xs5, .layui-col-xs6, .layui-col-xs7, .layui-col-xs8, .layui-col-xs9 { + position: relative; + display: block; + box-sizing: border-box +} + +.layui-col-xs1, .layui-col-xs10, .layui-col-xs11, .layui-col-xs12, .layui-col-xs2, .layui-col-xs3, .layui-col-xs4, .layui-col-xs5, .layui-col-xs6, .layui-col-xs7, .layui-col-xs8, .layui-col-xs9 { + float: left +} + +.layui-col-xs1 { + width: 8.33333333% +} + +.layui-col-xs2 { + width: 16.66666667% +} + +.layui-col-xs3 { + width: 25% +} + +.layui-col-xs4 { + width: 33.33333333% +} + +.layui-col-xs5 { + width: 41.66666667% +} + +.layui-col-xs6 { + width: 50% +} + +.layui-col-xs7 { + width: 58.33333333% +} + +.layui-col-xs8 { + width: 66.66666667% +} + +.layui-col-xs9 { + width: 75% +} + +.layui-col-xs10 { + width: 83.33333333% +} + +.layui-col-xs11 { + width: 91.66666667% +} + +.layui-col-xs12 { + width: 100% +} + +.layui-col-xs-offset1 { + margin-left: 8.33333333% +} + +.layui-col-xs-offset2 { + margin-left: 16.66666667% +} + +.layui-col-xs-offset3 { + margin-left: 25% +} + +.layui-col-xs-offset4 { + margin-left: 33.33333333% +} + +.layui-col-xs-offset5 { + margin-left: 41.66666667% +} + +.layui-col-xs-offset6 { + margin-left: 50% +} + +.layui-col-xs-offset7 { + margin-left: 58.33333333% +} + +.layui-col-xs-offset8 { + margin-left: 66.66666667% +} + +.layui-col-xs-offset9 { + margin-left: 75% +} + +.layui-col-xs-offset10 { + margin-left: 83.33333333% +} + +.layui-col-xs-offset11 { + margin-left: 91.66666667% +} + +.layui-col-xs-offset12 { + margin-left: 100% +} + +@media screen and (max-width: 768px) { + .layui-hide-xs { + display: none !important + } + + .layui-show-xs-block { + display: block !important + } + + .layui-show-xs-inline { + display: inline !important + } + + .layui-show-xs-inline-block { + display: inline-block !important + } +} + +@media screen and (min-width: 768px) { + .layui-container { + width: 750px + } + + .layui-hide-sm { + display: none !important + } + + .layui-show-sm-block { + display: block !important + } + + .layui-show-sm-inline { + display: inline !important + } + + .layui-show-sm-inline-block { + display: inline-block !important + } + + .layui-col-sm1, .layui-col-sm10, .layui-col-sm11, .layui-col-sm12, .layui-col-sm2, .layui-col-sm3, .layui-col-sm4, .layui-col-sm5, .layui-col-sm6, .layui-col-sm7, .layui-col-sm8, .layui-col-sm9 { + float: left + } + + .layui-col-sm1 { + width: 8.33333333% + } + + .layui-col-sm2 { + width: 16.66666667% + } + + .layui-col-sm3 { + width: 25% + } + + .layui-col-sm4 { + width: 33.33333333% + } + + .layui-col-sm5 { + width: 41.66666667% + } + + .layui-col-sm6 { + width: 50% + } + + .layui-col-sm7 { + width: 58.33333333% + } + + .layui-col-sm8 { + width: 66.66666667% + } + + .layui-col-sm9 { + width: 75% + } + + .layui-col-sm10 { + width: 83.33333333% + } + + .layui-col-sm11 { + width: 91.66666667% + } + + .layui-col-sm12 { + width: 100% + } + + .layui-col-sm-offset1 { + margin-left: 8.33333333% + } + + .layui-col-sm-offset2 { + margin-left: 16.66666667% + } + + .layui-col-sm-offset3 { + margin-left: 25% + } + + .layui-col-sm-offset4 { + margin-left: 33.33333333% + } + + .layui-col-sm-offset5 { + margin-left: 41.66666667% + } + + .layui-col-sm-offset6 { + margin-left: 50% + } + + .layui-col-sm-offset7 { + margin-left: 58.33333333% + } + + .layui-col-sm-offset8 { + margin-left: 66.66666667% + } + + .layui-col-sm-offset9 { + margin-left: 75% + } + + .layui-col-sm-offset10 { + margin-left: 83.33333333% + } + + .layui-col-sm-offset11 { + margin-left: 91.66666667% + } + + .layui-col-sm-offset12 { + margin-left: 100% + } +} + +@media screen and (min-width: 992px) { + .layui-container { + width: 970px + } + + .layui-hide-md { + display: none !important + } + + .layui-show-md-block { + display: block !important + } + + .layui-show-md-inline { + display: inline !important + } + + .layui-show-md-inline-block { + display: inline-block !important + } + + .layui-col-md1, .layui-col-md10, .layui-col-md11, .layui-col-md12, .layui-col-md2, .layui-col-md3, .layui-col-md4, .layui-col-md5, .layui-col-md6, .layui-col-md7, .layui-col-md8, .layui-col-md9 { + float: left + } + + .layui-col-md1 { + width: 8.33333333% + } + + .layui-col-md2 { + width: 16.66666667% + } + + .layui-col-md3 { + width: 25% + } + + .layui-col-md4 { + width: 33.33333333% + } + + .layui-col-md5 { + width: 41.66666667% + } + + .layui-col-md6 { + width: 50% + } + + .layui-col-md7 { + width: 58.33333333% + } + + .layui-col-md8 { + width: 66.66666667% + } + + .layui-col-md9 { + width: 75% + } + + .layui-col-md10 { + width: 83.33333333% + } + + .layui-col-md11 { + width: 91.66666667% + } + + .layui-col-md12 { + width: 100% + } + + .layui-col-md-offset1 { + margin-left: 8.33333333% + } + + .layui-col-md-offset2 { + margin-left: 16.66666667% + } + + .layui-col-md-offset3 { + margin-left: 25% + } + + .layui-col-md-offset4 { + margin-left: 33.33333333% + } + + .layui-col-md-offset5 { + margin-left: 41.66666667% + } + + .layui-col-md-offset6 { + margin-left: 50% + } + + .layui-col-md-offset7 { + margin-left: 58.33333333% + } + + .layui-col-md-offset8 { + margin-left: 66.66666667% + } + + .layui-col-md-offset9 { + margin-left: 75% + } + + .layui-col-md-offset10 { + margin-left: 83.33333333% + } + + .layui-col-md-offset11 { + margin-left: 91.66666667% + } + + .layui-col-md-offset12 { + margin-left: 100% + } +} + +@media screen and (min-width: 1200px) { + .layui-container { + width: 1170px + } + + .layui-hide-lg { + display: none !important + } + + .layui-show-lg-block { + display: block !important + } + + .layui-show-lg-inline { + display: inline !important + } + + .layui-show-lg-inline-block { + display: inline-block !important + } + + .layui-col-lg1, .layui-col-lg10, .layui-col-lg11, .layui-col-lg12, .layui-col-lg2, .layui-col-lg3, .layui-col-lg4, .layui-col-lg5, .layui-col-lg6, .layui-col-lg7, .layui-col-lg8, .layui-col-lg9 { + float: left + } + + .layui-col-lg1 { + width: 8.33333333% + } + + .layui-col-lg2 { + width: 16.66666667% + } + + .layui-col-lg3 { + width: 25% + } + + .layui-col-lg4 { + width: 33.33333333% + } + + .layui-col-lg5 { + width: 41.66666667% + } + + .layui-col-lg6 { + width: 50% + } + + .layui-col-lg7 { + width: 58.33333333% + } + + .layui-col-lg8 { + width: 66.66666667% + } + + .layui-col-lg9 { + width: 75% + } + + .layui-col-lg10 { + width: 83.33333333% + } + + .layui-col-lg11 { + width: 91.66666667% + } + + .layui-col-lg12 { + width: 100% + } + + .layui-col-lg-offset1 { + margin-left: 8.33333333% + } + + .layui-col-lg-offset2 { + margin-left: 16.66666667% + } + + .layui-col-lg-offset3 { + margin-left: 25% + } + + .layui-col-lg-offset4 { + margin-left: 33.33333333% + } + + .layui-col-lg-offset5 { + margin-left: 41.66666667% + } + + .layui-col-lg-offset6 { + margin-left: 50% + } + + .layui-col-lg-offset7 { + margin-left: 58.33333333% + } + + .layui-col-lg-offset8 { + margin-left: 66.66666667% + } + + .layui-col-lg-offset9 { + margin-left: 75% + } + + .layui-col-lg-offset10 { + margin-left: 83.33333333% + } + + .layui-col-lg-offset11 { + margin-left: 91.66666667% + } + + .layui-col-lg-offset12 { + margin-left: 100% + } +} + +.layui-col-space1 { + margin: -.5px +} + +.layui-col-space1 > * { + padding: .5px +} + +.layui-col-space2 { + margin: -1px +} + +.layui-col-space2 > * { + padding: 1px +} + +.layui-col-space4 { + margin: -2px +} + +.layui-col-space4 > * { + padding: 2px +} + +.layui-col-space5 { + margin: -2.5px +} + +.layui-col-space5 > * { + padding: 2.5px +} + +.layui-col-space6 { + margin: -3px +} + +.layui-col-space6 > * { + padding: 3px +} + +.layui-col-space8 { + margin: -4px +} + +.layui-col-space8 > * { + padding: 4px +} + +.layui-col-space10 { + margin: -5px +} + +.layui-col-space10 > * { + padding: 5px +} + +.layui-col-space12 { + margin: -6px +} + +.layui-col-space12 > * { + padding: 6px +} + +.layui-col-space14 { + margin: -7px +} + +.layui-col-space14 > * { + padding: 7px +} + +.layui-col-space15 { + margin: -7.5px +} + +.layui-col-space15 > * { + padding: 7.5px +} + +.layui-col-space16 { + margin: -8px +} + +.layui-col-space16 > * { + padding: 8px +} + +.layui-col-space18 { + margin: -9px +} + +.layui-col-space18 > * { + padding: 9px +} + +.layui-col-space20 { + margin: -10px +} + +.layui-col-space20 > * { + padding: 10px +} + +.layui-col-space22 { + margin: -11px +} + +.layui-col-space22 > * { + padding: 11px +} + +.layui-col-space24 { + margin: -12px +} + +.layui-col-space24 > * { + padding: 12px +} + +.layui-col-space25 { + margin: -12.5px +} + +.layui-col-space25 > * { + padding: 12.5px +} + +.layui-col-space26 { + margin: -13px +} + +.layui-col-space26 > * { + padding: 13px +} + +.layui-col-space28 { + margin: -14px +} + +.layui-col-space28 > * { + padding: 14px +} + +.layui-col-space30 { + margin: -15px +} + +.layui-col-space30 > * { + padding: 15px +} + +.layui-btn, .layui-input, .layui-select, .layui-textarea, .layui-upload-button { + outline: 0; + -webkit-appearance: none; + transition: all .3s; + -webkit-transition: all .3s; + box-sizing: border-box +} + +.layui-elem-quote { + margin-bottom: 10px; + padding: 15px; + line-height: 1.6; + border-left: 5px solid #5FB878; + border-radius: 0 2px 2px 0; + background-color: #FAFAFA +} + +.layui-quote-nm { + border-style: solid; + border-width: 1px 1px 1px 5px; + background: 0 0 +} + +.layui-elem-field { + margin-bottom: 10px; + padding: 0; + border-width: 1px; + border-style: solid +} + +.layui-elem-field legend { + margin-left: 20px; + padding: 0 10px; + font-size: 20px; + font-weight: 300 +} + +.layui-field-title { + margin: 10px 0 20px; + border-width: 1px 0 0 +} + +.layui-field-box { + padding: 15px +} + +.layui-field-title .layui-field-box { + padding: 10px 0 +} + +.layui-progress { + position: relative; + height: 6px; + border-radius: 20px; + background-color: #eee +} + +.layui-progress-bar { + position: absolute; + left: 0; + top: 0; + width: 0; + max-width: 100%; + height: 6px; + border-radius: 20px; + text-align: right; + background-color: #5FB878; + transition: all .3s; + -webkit-transition: all .3s +} + +.layui-progress-big, .layui-progress-big .layui-progress-bar { + height: 18px; + line-height: 18px +} + +.layui-progress-text { + position: relative; + top: -20px; + line-height: 18px; + font-size: 12px; + color: #666 +} + +.layui-progress-big .layui-progress-text { + position: static; + padding: 0 10px; + color: #fff +} + +.layui-collapse { + border-width: 1px; + border-style: solid; + border-radius: 2px +} + +.layui-colla-content, .layui-colla-item { + border-top-width: 1px; + border-top-style: solid +} + +.layui-colla-item:first-child { + border-top: none +} + +.layui-colla-title { + position: relative; + height: 42px; + line-height: 42px; + padding: 0 15px 0 35px; + color: #333; + background-color: #FAFAFA; + cursor: pointer; + font-size: 14px; + overflow: hidden +} + +.layui-colla-content { + display: none; + padding: 10px 15px; + line-height: 1.6; + color: #666 +} + +.layui-colla-icon { + position: absolute; + left: 15px; + top: 0; + font-size: 14px +} + +.layui-card { + margin-bottom: 15px; + border-radius: 2px; + background-color: #fff; + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .05) +} + +.layui-card:last-child { + margin-bottom: 0 +} + +.layui-card-header { + position: relative; + height: 42px; + line-height: 42px; + padding: 0 15px; + border-bottom: 1px solid #f6f6f6; + color: #333; + border-radius: 2px 2px 0 0; + font-size: 14px +} + +.layui-card-body { + position: relative; + padding: 10px 15px; + line-height: 24px +} + +.layui-card-body[pad15] { + padding: 15px +} + +.layui-card-body[pad20] { + padding: 20px +} + +.layui-card-body .layui-table { + margin: 5px 0 +} + +.layui-card .layui-tab { + margin: 0 +} + +.layui-panel { + position: relative; + border-width: 1px; + border-style: solid; + border-radius: 2px; + box-shadow: 1px 1px 4px rgb(0 0 0 / 8%); + background-color: #fff; + color: #666 +} + +.layui-bg-black, .layui-bg-blue, .layui-bg-cyan, .layui-bg-green, .layui-bg-orange, .layui-bg-red { + color: #fff !important +} + +.layui-panel-window { + position: relative; + padding: 15px; + border-radius: 0; + border-top: 5px solid #eee; + background-color: #fff +} + +.layui-border, .layui-border-black, .layui-border-blue, .layui-border-cyan, .layui-border-green, .layui-border-orange, .layui-border-red { + border-width: 1px; + border-style: solid +} + +.layui-auxiliar-moving { + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + width: 100%; + height: 100%; + background: 0 0; + z-index: 9999999999 +} + +.layui-form-label, .layui-form-mid, .layui-form-select, .layui-input-block, .layui-input-inline, .layui-textarea { + position: relative +} + +.layui-bg-red { + background-color: #FF5722 !important +} + +.layui-bg-orange { + background-color: #FFB800 !important +} + +.layui-bg-green { + background-color: #009688 !important +} + +.layui-bg-cyan { + background-color: #2F4056 !important +} + +.layui-bg-blue { + background-color: #1E9FFF !important +} + +.layui-bg-black { + background-color: #393D49 !important +} + +.layui-bg-gray { + background-color: #FAFAFA !important; + color: #666 !important +} + +.layui-badge-rim, .layui-border, .layui-colla-content, .layui-colla-item, .layui-collapse, .layui-elem-field, .layui-form-pane .layui-form-item[pane], .layui-form-pane .layui-form-label, .layui-input, .layui-layedit, .layui-layedit-tool, .layui-panel, .layui-quote-nm, .layui-select, .layui-tab-bar, .layui-tab-card, .layui-tab-title, .layui-tab-title .layui-this:after, .layui-textarea { + border-color: #eee +} + +.layui-border { + color: #666 !important +} + +.layui-border-red { + border-color: #FF5722 !important; + color: #FF5722 !important +} + +.layui-border-orange { + border-color: #FFB800 !important; + color: #FFB800 !important +} + +.layui-border-green { + border-color: #009688 !important; + color: #009688 !important +} + +.layui-border-cyan { + border-color: #2F4056 !important; + color: #2F4056 !important +} + +.layui-border-blue { + border-color: #1E9FFF !important; + color: #1E9FFF !important +} + +.layui-border-black { + border-color: #393D49 !important; + color: #393D49 !important +} + +.layui-timeline-item:before { + background-color: #eee +} + +.layui-text { + line-height: 1.6; + font-size: 14px; + color: #666 +} + +.layui-text h1, .layui-text h2, .layui-text h3 { + font-weight: 500; + color: #333 +} + +.layui-text h1 { + font-size: 30px +} + +.layui-text h2 { + font-size: 24px +} + +.layui-text h3 { + font-size: 18px +} + +.layui-text a:not(.layui-btn) { + color: #01AAED +} + +.layui-text a:not(.layui-btn):hover { + text-decoration: underline +} + +.layui-text ul { + padding: 5px 0 5px 15px +} + +.layui-text ul li { + margin-top: 5px; + list-style-type: disc +} + +.layui-text em, .layui-word-aux { + color: #999 !important; + padding-left: 5px !important; + padding-right: 5px !important +} + +.layui-font-12 { + font-size: 12px +} + +.layui-font-14 { + font-size: 14px +} + +.layui-font-16 { + font-size: 16px +} + +.layui-font-18 { + font-size: 18px +} + +.layui-font-20 { + font-size: 20px +} + +.layui-font-red { + color: #FF5722 !important +} + +.layui-font-orange { + color: #FFB800 !important +} + +.layui-font-green { + color: #009688 !important +} + +.layui-font-cyan { + color: #2F4056 !important +} + +.layui-font-blue { + color: #01AAED !important +} + +.layui-font-black { + color: #000 !important +} + +.layui-font-gray { + color: #c2c2c2 !important +} + +.layui-btn { + display: inline-block; + height: 38px; + line-height: 38px; + padding: 0 18px; + border: 1px solid transparent; + background-color: #009688; + color: #fff; + white-space: nowrap; + text-align: center; + font-size: 14px; + border-radius: 2px; + cursor: pointer +} + +.layui-btn:hover { + opacity: .8; + filter: alpha(opacity=80); + color: #fff +} + +.layui-btn:active { + opacity: 1; + filter: alpha(opacity=100) +} + +.layui-btn + .layui-btn { + margin-left: 10px +} + +.layui-btn-container { + font-size: 0 +} + +.layui-btn-container .layui-btn { + margin-right: 10px; + margin-bottom: 10px +} + +.layui-btn-container .layui-btn + .layui-btn { + margin-left: 0 +} + +.layui-table .layui-btn-container .layui-btn { + margin-bottom: 9px +} + +.layui-btn-radius { + border-radius: 100px +} + +.layui-btn .layui-icon { + padding: 0 2px; + vertical-align: middle \9; + vertical-align: bottom +} + +.layui-btn-primary { + border-color: #d2d2d2; + background: 0 0; + color: #666 +} + +.layui-btn-primary:hover { + border-color: #009688; + color: #333 +} + +.layui-btn-normal { + background-color: #1E9FFF +} + +.layui-btn-warm { + background-color: #FFB800 +} + +.layui-btn-danger { + background-color: #FF5722 +} + +.layui-btn-checked { + background-color: #5FB878 +} + +.layui-btn-disabled, .layui-btn-disabled:active, .layui-btn-disabled:hover { + border-color: #eee; + background-color: #FBFBFB; + color: #d2d2d2; + cursor: not-allowed; + opacity: 1 +} + +.layui-btn-lg { + height: 44px; + line-height: 44px; + padding: 0 25px; + font-size: 16px +} + +.layui-btn-sm { + height: 30px; + line-height: 30px; + padding: 0 10px; + font-size: 12px +} + +.layui-btn-xs { + height: 22px; + line-height: 22px; + padding: 0 5px; + font-size: 12px +} + +.layui-btn-xs i { + font-size: 12px !important +} + +.layui-btn-group { + display: inline-block; + vertical-align: middle; + font-size: 0 +} + +.layui-btn-group .layui-btn { + margin-left: 0 !important; + margin-right: 0 !important; + border-left: 1px solid rgba(255, 255, 255, .5); + border-radius: 0 +} + +.layui-btn-group .layui-btn-primary { + border-left: none +} + +.layui-btn-group .layui-btn-primary:hover { + border-color: #d2d2d2; + color: #009688 +} + +.layui-btn-group .layui-btn:first-child { + border-left: none; + border-radius: 2px 0 0 2px +} + +.layui-btn-group .layui-btn-primary:first-child { + border-left: 1px solid #d2d2d2 +} + +.layui-btn-group .layui-btn:last-child { + border-radius: 0 2px 2px 0 +} + +.layui-btn-group .layui-btn + .layui-btn { + margin-left: 0 +} + +.layui-btn-group + .layui-btn-group { + margin-left: 10px +} + +.layui-btn-fluid { + width: 100% +} + +.layui-input, .layui-select, .layui-textarea { + height: 38px; + line-height: 1.3; + line-height: 38px \9; + border-width: 1px; + border-style: solid; + background-color: #fff; + border-radius: 2px +} + +.layui-input::-webkit-input-placeholder, .layui-select::-webkit-input-placeholder, .layui-textarea::-webkit-input-placeholder { + line-height: 1.3 +} + +.layui-input, .layui-textarea { + display: block; + width: 100%; + padding-left: 10px +} + +.layui-input:hover, .layui-textarea:hover { + border-color: #eee !important +} + +.layui-input:focus, .layui-textarea:focus { + border-color: #d2d2d2 !important +} + +.layui-textarea { + min-height: 100px; + height: auto; + line-height: 20px; + padding: 6px 10px; + resize: vertical +} + +.layui-select { + padding: 0 10px +} + +.layui-form input[type=checkbox], .layui-form input[type=radio], .layui-form select { + display: none +} + +.layui-form [lay-ignore] { + display: initial +} + +.layui-form-item { + margin-bottom: 15px; + clear: both; + *zoom: 1 +} + +.layui-form-item:after { + content: '\20'; + clear: both; + *zoom: 1; + display: block; + height: 0 +} + +.layui-form-label { + float: left; + display: block; + padding: 9px 15px; + width: 80px; + font-weight: 400; + line-height: 20px; + text-align: right +} + +.layui-form-label-col { + display: block; + float: none; + padding: 9px 0; + line-height: 20px; + text-align: left +} + +.layui-form-item .layui-inline { + margin-bottom: 5px; + margin-right: 10px +} + +.layui-input-block { + margin-left: 110px; + min-height: 36px +} + +.layui-input-inline { + display: inline-block; + vertical-align: middle +} + +.layui-form-item .layui-input-inline { + float: left; + width: 190px; + margin-right: 10px +} + +.layui-form-text .layui-input-inline { + width: auto +} + +.layui-form-mid { + float: left; + display: block; + padding: 9px 0 !important; + line-height: 20px; + margin-right: 10px +} + +.layui-form-danger + .layui-form-select .layui-input, .layui-form-danger:focus { + border-color: #FF5722 !important +} + +.layui-form-select .layui-input { + padding-right: 30px; + cursor: pointer +} + +.layui-form-select .layui-edge { + position: absolute; + right: 10px; + top: 50%; + margin-top: -3px; + cursor: pointer; + border-width: 6px; + border-top-color: #c2c2c2; + border-top-style: solid; + transition: all .3s; + -webkit-transition: all .3s +} + +.layui-form-select dl { + display: none; + position: absolute; + left: 0; + top: 42px; + padding: 5px 0; + z-index: 899; + min-width: 100%; + border: 1px solid #d2d2d2; + max-height: 300px; + overflow-y: auto; + background-color: #fff; + border-radius: 2px; + box-shadow: 0 2px 4px rgba(0, 0, 0, .12); + box-sizing: border-box +} + +.layui-form-select dl dd, .layui-form-select dl dt { + padding: 0 10px; + line-height: 36px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis +} + +.layui-form-select dl dt { + font-size: 12px; + color: #999 +} + +.layui-form-select dl dd { + cursor: pointer +} + +.layui-form-select dl dd:hover { + background-color: #F6F6F6; + -webkit-transition: .5s all; + transition: .5s all +} + +.layui-form-select .layui-select-group dd { + padding-left: 20px +} + +.layui-form-select dl dd.layui-select-tips { + padding-left: 10px !important; + color: #999 +} + +.layui-form-select dl dd.layui-this { + background-color: #5FB878; + color: #fff +} + +.layui-form-checkbox, .layui-form-select dl dd.layui-disabled { + background-color: #fff +} + +.layui-form-selected dl { + display: block +} + +.layui-form-checkbox, .layui-form-checkbox *, .layui-form-switch { + display: inline-block; + vertical-align: middle +} + +.layui-form-selected .layui-edge { + margin-top: -9px; + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + margin-top: -3px \9 +} + +:root .layui-form-selected .layui-edge { + margin-top: -9px \0/ IE9 +} + +.layui-form-selectup dl { + top: auto; + bottom: 42px +} + +.layui-select-none { + margin: 5px 0; + text-align: center; + color: #999 +} + +.layui-select-disabled .layui-disabled { + border-color: #eee !important +} + +.layui-select-disabled .layui-edge { + border-top-color: #d2d2d2 +} + +.layui-form-checkbox { + position: relative; + height: 30px; + line-height: 30px; + margin-right: 10px; + padding-right: 30px; + cursor: pointer; + font-size: 0; + -webkit-transition: .1s linear; + transition: .1s linear; + box-sizing: border-box +} + +.layui-form-checkbox span { + padding: 0 10px; + height: 100%; + font-size: 14px; + border-radius: 2px 0 0 2px; + background-color: #d2d2d2; + color: #fff; + overflow: hidden +} + +.layui-form-checkbox:hover span { + background-color: #c2c2c2 +} + +.layui-form-checkbox i { + position: absolute; + right: 0; + top: 0; + width: 30px; + height: 28px; + border: 1px solid #d2d2d2; + border-left: none; + border-radius: 0 2px 2px 0; + color: #fff; + font-size: 20px; + text-align: center +} + +.layui-form-checkbox:hover i { + border-color: #c2c2c2; + color: #c2c2c2 +} + +.layui-form-checked, .layui-form-checked:hover { + border-color: #5FB878 +} + +.layui-form-checked span, .layui-form-checked:hover span { + background-color: #5FB878 +} + +.layui-form-checked i, .layui-form-checked:hover i { + color: #5FB878 +} + +.layui-form-item .layui-form-checkbox { + margin-top: 4px +} + +.layui-form-checkbox[lay-skin=primary] { + height: auto !important; + line-height: normal !important; + min-width: 18px; + min-height: 18px; + border: none !important; + margin-right: 0; + padding-left: 28px; + padding-right: 0; + background: 0 0 +} + +.layui-form-checkbox[lay-skin=primary] span { + padding-left: 0; + padding-right: 15px; + line-height: 18px; + background: 0 0; + color: #666 +} + +.layui-form-checkbox[lay-skin=primary] i { + right: auto; + left: 0; + width: 16px; + height: 16px; + line-height: 16px; + border: 1px solid #d2d2d2; + font-size: 12px; + border-radius: 2px; + background-color: #fff; + -webkit-transition: .1s linear; + transition: .1s linear +} + +.layui-form-checkbox[lay-skin=primary]:hover i { + border-color: #5FB878; + color: #fff +} + +.layui-form-checked[lay-skin=primary] i { + border-color: #5FB878 !important; + background-color: #5FB878; + color: #fff +} + +.layui-checkbox-disbaled[lay-skin=primary] span { + background: 0 0 !important; + color: #c2c2c2 !important +} + +.layui-checkbox-disbaled[lay-skin=primary]:hover i { + border-color: #d2d2d2 +} + +.layui-form-item .layui-form-checkbox[lay-skin=primary] { + margin-top: 10px +} + +.layui-form-switch { + position: relative; + height: 22px; + line-height: 22px; + min-width: 35px; + padding: 0 5px; + margin-top: 8px; + border: 1px solid #d2d2d2; + border-radius: 20px; + cursor: pointer; + background-color: #fff; + -webkit-transition: .1s linear; + transition: .1s linear +} + +.layui-form-switch i { + position: absolute; + left: 5px; + top: 3px; + width: 16px; + height: 16px; + border-radius: 20px; + background-color: #d2d2d2; + -webkit-transition: .1s linear; + transition: .1s linear +} + +.layui-form-switch em { + position: relative; + top: 0; + width: 25px; + margin-left: 21px; + padding: 0 !important; + text-align: center !important; + color: #999 !important; + font-style: normal !important; + font-size: 12px +} + +.layui-form-onswitch { + border-color: #5FB878; + background-color: #5FB878 +} + +.layui-checkbox-disbaled, .layui-checkbox-disbaled i { + border-color: #eee !important +} + +.layui-form-onswitch i { + left: 100%; + margin-left: -21px; + background-color: #fff +} + +.layui-form-onswitch em { + margin-left: 5px; + margin-right: 21px; + color: #fff !important +} + +.layui-checkbox-disbaled span { + background-color: #eee !important +} + +.layui-checkbox-disbaled em { + color: #d2d2d2 !important +} + +.layui-checkbox-disbaled:hover i { + color: #fff !important +} + +[lay-radio] { + display: none +} + +.layui-form-radio, .layui-form-radio * { + display: inline-block; + vertical-align: middle +} + +.layui-form-radio { + line-height: 28px; + margin: 6px 10px 0 0; + padding-right: 10px; + cursor: pointer; + font-size: 0 +} + +.layui-form-radio * { + font-size: 14px +} + +.layui-form-radio > i { + margin-right: 8px; + font-size: 22px; + color: #c2c2c2 +} + +.layui-form-radio:hover *, .layui-form-radioed, .layui-form-radioed > i { + color: #5FB878 +} + +.layui-radio-disbaled > i { + color: #eee !important +} + +.layui-radio-disbaled * { + color: #c2c2c2 !important +} + +.layui-form-pane .layui-form-label { + width: 110px; + padding: 8px 15px; + height: 38px; + line-height: 20px; + border-width: 1px; + border-style: solid; + border-radius: 2px 0 0 2px; + text-align: center; + background-color: #FBFBFB; + overflow: hidden; + box-sizing: border-box +} + +.layui-form-pane .layui-input-inline { + margin-left: -1px +} + +.layui-form-pane .layui-input-block { + margin-left: 110px; + left: -1px +} + +.layui-form-pane .layui-input { + border-radius: 0 2px 2px 0 +} + +.layui-form-pane .layui-form-text .layui-form-label { + float: none; + width: 100%; + border-radius: 2px; + box-sizing: border-box; + text-align: left +} + +.layui-form-pane .layui-form-text .layui-input-inline { + display: block; + margin: 0; + top: -1px; + clear: both +} + +.layui-form-pane .layui-form-text .layui-input-block { + margin: 0; + left: 0; + top: -1px +} + +.layui-form-pane .layui-form-text .layui-textarea { + min-height: 100px; + border-radius: 0 0 2px 2px +} + +.layui-form-pane .layui-form-checkbox { + margin: 4px 0 4px 10px +} + +.layui-form-pane .layui-form-radio, .layui-form-pane .layui-form-switch { + margin-top: 6px; + margin-left: 10px +} + +.layui-form-pane .layui-form-item[pane] { + position: relative; + border-width: 1px; + border-style: solid +} + +.layui-form-pane .layui-form-item[pane] .layui-form-label { + position: absolute; + left: 0; + top: 0; + height: 100%; + border-width: 0 1px 0 0 +} + +.layui-form-pane .layui-form-item[pane] .layui-input-inline { + margin-left: 110px +} + +@media screen and (max-width: 450px) { + .layui-form-item .layui-form-label { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap + } + + .layui-form-item .layui-inline { + display: block; + margin-right: 0; + margin-bottom: 20px; + clear: both + } + + .layui-form-item .layui-inline:after { + content: '\20'; + clear: both; + display: block; + height: 0 + } + + .layui-form-item .layui-input-inline { + display: block; + float: none; + left: -3px; + width: auto; + margin: 0 0 10px 112px + } + + .layui-form-item .layui-input-inline + .layui-form-mid { + margin-left: 110px; + top: -5px; + padding: 0 + } + + .layui-form-item .layui-form-checkbox { + margin-right: 5px; + margin-bottom: 5px + } +} + +.layui-layedit { + border-width: 1px; + border-style: solid; + border-radius: 2px +} + +.layui-layedit-tool { + padding: 3px 5px; + border-bottom-width: 1px; + border-bottom-style: solid; + font-size: 0 +} + +.layedit-tool-fixed { + position: fixed; + top: 0; + border-top: 1px solid #eee +} + +.layui-layedit-tool .layedit-tool-mid, .layui-layedit-tool .layui-icon { + display: inline-block; + vertical-align: middle; + text-align: center; + font-size: 14px +} + +.layui-layedit-tool .layui-icon { + position: relative; + width: 32px; + height: 30px; + line-height: 30px; + margin: 3px 5px; + color: #777; + cursor: pointer; + border-radius: 2px +} + +.layui-layedit-tool .layui-icon:hover { + color: #393D49 +} + +.layui-layedit-tool .layui-icon:active { + color: #000 +} + +.layui-layedit-tool .layedit-tool-active { + background-color: #eee; + color: #000 +} + +.layui-layedit-tool .layui-disabled, .layui-layedit-tool .layui-disabled:hover { + color: #d2d2d2; + cursor: not-allowed +} + +.layui-layedit-tool .layedit-tool-mid { + width: 1px; + height: 18px; + margin: 0 10px; + background-color: #d2d2d2 +} + +.layedit-tool-html { + width: 50px !important; + font-size: 30px !important +} + +.layedit-tool-b, .layedit-tool-code, .layedit-tool-help { + font-size: 16px !important +} + +.layedit-tool-d, .layedit-tool-face, .layedit-tool-image, .layedit-tool-unlink { + font-size: 18px !important +} + +.layedit-tool-image input { + position: absolute; + font-size: 0; + left: 0; + top: 0; + width: 100%; + height: 100%; + opacity: .01; + filter: Alpha(opacity=1); + cursor: pointer +} + +.layui-layedit-iframe iframe { + display: block; + width: 100% +} + +#LAY_layedit_code { + overflow: hidden +} + +.layui-laypage { + display: inline-block; + *display: inline; + *zoom: 1; + vertical-align: middle; + margin: 10px 0; + font-size: 0 +} + +.layui-laypage > a:first-child, .layui-laypage > a:first-child em { + border-radius: 2px 0 0 2px +} + +.layui-laypage > a:last-child, .layui-laypage > a:last-child em { + border-radius: 0 2px 2px 0 +} + +.layui-laypage > :first-child { + margin-left: 0 !important +} + +.layui-laypage > :last-child { + margin-right: 0 !important +} + +.layui-laypage a, .layui-laypage button, .layui-laypage input, .layui-laypage select, .layui-laypage span { + border: 1px solid #eee +} + +.layui-laypage a, .layui-laypage span { + display: inline-block; + *display: inline; + *zoom: 1; + vertical-align: middle; + padding: 0 15px; + height: 28px; + line-height: 28px; + margin: 0 -1px 5px 0; + background-color: #fff; + color: #333; + font-size: 12px +} + +.layui-flow-more a *, .layui-laypage input, .layui-table-view select[lay-ignore] { + display: inline-block +} + +.layui-laypage a:hover { + color: #009688 +} + +.layui-laypage em { + font-style: normal +} + +.layui-laypage .layui-laypage-spr { + color: #999; + font-weight: 700 +} + +.layui-laypage a { + text-decoration: none +} + +.layui-laypage .layui-laypage-curr { + position: relative +} + +.layui-laypage .layui-laypage-curr em { + position: relative; + color: #fff +} + +.layui-laypage .layui-laypage-curr .layui-laypage-em { + position: absolute; + left: -1px; + top: -1px; + padding: 1px; + width: 100%; + height: 100%; + background-color: #009688 +} + +.layui-laypage-em { + border-radius: 2px +} + +.layui-laypage-next em, .layui-laypage-prev em { + font-family: Sim sun; + font-size: 16px +} + +.layui-laypage .layui-laypage-count, .layui-laypage .layui-laypage-limits, .layui-laypage .layui-laypage-refresh, .layui-laypage .layui-laypage-skip { + margin-left: 10px; + margin-right: 10px; + padding: 0; + border: none +} + +.layui-laypage .layui-laypage-limits, .layui-laypage .layui-laypage-refresh { + vertical-align: top +} + +.layui-laypage .layui-laypage-refresh i { + font-size: 18px; + cursor: pointer +} + +.layui-laypage select { + height: 22px; + padding: 3px; + border-radius: 2px; + cursor: pointer +} + +.layui-laypage .layui-laypage-skip { + height: 30px; + line-height: 30px; + color: #999 +} + +.layui-laypage button, .layui-laypage input { + height: 30px; + line-height: 30px; + border-radius: 2px; + vertical-align: top; + background-color: #fff; + box-sizing: border-box +} + +.layui-laypage input { + width: 40px; + margin: 0 10px; + padding: 0 3px; + text-align: center +} + +.layui-laypage input:focus, .layui-laypage select:focus { + border-color: #009688 !important +} + +.layui-laypage button { + margin-left: 10px; + padding: 0 10px; + cursor: pointer +} + +.layui-table, .layui-table-view { + margin: 10px 0 +} + +.layui-flow-more { + margin: 10px 0; + text-align: center; + color: #999; + font-size: 14px +} + +.layui-flow-more a { + height: 32px; + line-height: 32px +} + +.layui-flow-more a * { + vertical-align: top +} + +.layui-flow-more a cite { + padding: 0 20px; + border-radius: 3px; + background-color: #eee; + color: #333; + font-style: normal +} + +.layui-flow-more a cite:hover { + opacity: .8 +} + +.layui-flow-more a i { + font-size: 30px; + color: #737383 +} + +.layui-table { + width: 100%; + background-color: #fff; + color: #666 +} + +.layui-table tr { + transition: all .3s; + -webkit-transition: all .3s +} + +.layui-table th { + text-align: left; + font-weight: 400 +} + +.layui-table tbody tr:hover, .layui-table thead tr, .layui-table-click, .layui-table-header, .layui-table-hover, .layui-table-mend, .layui-table-patch, .layui-table-tool, .layui-table-total, .layui-table-total tr, .layui-table[lay-even] tr:nth-child(even) { + background-color: #FAFAFA +} + +.layui-table td, .layui-table th, .layui-table-col-set, .layui-table-fixed-r, .layui-table-grid-down, .layui-table-header, .layui-table-page, .layui-table-tips-main, .layui-table-tool, .layui-table-total, .layui-table-view, .layui-table[lay-skin=line], .layui-table[lay-skin=row] { + border-width: 1px; + border-style: solid; + border-color: #eee +} + +.layui-table td, .layui-table th { + position: relative; + padding: 9px 15px; + min-height: 20px; + line-height: 20px; + font-size: 14px +} + +.layui-table[lay-skin=line] td, .layui-table[lay-skin=line] th { + border-width: 0 0 1px +} + +.layui-table[lay-skin=row] td, .layui-table[lay-skin=row] th { + border-width: 0 1px 0 0 +} + +.layui-table[lay-skin=nob] td, .layui-table[lay-skin=nob] th { + border: none +} + +.layui-table img { + max-width: 100px +} + +.layui-table[lay-size=lg] td, .layui-table[lay-size=lg] th { + padding: 15px 30px +} + +.layui-table-view .layui-table[lay-size=lg] .layui-table-cell { + height: 40px; + line-height: 40px +} + +.layui-table[lay-size=sm] td, .layui-table[lay-size=sm] th { + font-size: 12px; + padding: 5px 10px +} + +.layui-table-view .layui-table[lay-size=sm] .layui-table-cell { + height: 20px; + line-height: 20px +} + +.layui-table[lay-data] { + display: none +} + +.layui-table-box { + position: relative; + overflow: hidden +} + +.layui-table-view .layui-table { + position: relative; + width: auto; + margin: 0 +} + +.layui-table-view .layui-table[lay-skin=line] { + border-width: 0 1px 0 0 +} + +.layui-table-view .layui-table[lay-skin=row] { + border-width: 0 0 1px +} + +.layui-table-view .layui-table td, .layui-table-view .layui-table th { + padding: 5px 0; + border-top: none; + border-left: none +} + +.layui-table-view .layui-table th.layui-unselect .layui-table-cell span { + cursor: pointer +} + +.layui-table-view .layui-table td { + cursor: default +} + +.layui-table-view .layui-table td[data-edit=text] { + cursor: text +} + +.layui-table-view .layui-form-checkbox[lay-skin=primary] i { + width: 18px; + height: 18px +} + +.layui-table-view .layui-form-radio { + line-height: 0; + padding: 0 +} + +.layui-table-view .layui-form-radio > i { + margin: 0; + font-size: 20px +} + +.layui-table-init { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + text-align: center; + z-index: 110 +} + +.layui-table-init .layui-icon { + position: absolute; + left: 50%; + top: 50%; + margin: -15px 0 0 -15px; + font-size: 30px; + color: #c2c2c2 +} + +.layui-table-header { + border-width: 0 0 1px; + overflow: hidden +} + +.layui-table-header .layui-table { + margin-bottom: -1px +} + +.layui-table-tool .layui-inline[lay-event] { + position: relative; + width: 26px; + height: 26px; + padding: 5px; + line-height: 16px; + margin-right: 10px; + text-align: center; + color: #333; + border: 1px solid #ccc; + cursor: pointer; + -webkit-transition: .5s all; + transition: .5s all +} + +.layui-table-tool .layui-inline[lay-event]:hover { + border: 1px solid #999 +} + +.layui-table-tool-temp { + padding-right: 120px +} + +.layui-table-tool-self { + position: absolute; + right: 17px; + top: 10px +} + +.layui-table-tool .layui-table-tool-self .layui-inline[lay-event] { + margin: 0 0 0 10px +} + +.layui-table-tool-panel { + position: absolute; + top: 29px; + left: -1px; + padding: 5px 0; + min-width: 150px; + min-height: 40px; + border: 1px solid #d2d2d2; + text-align: left; + overflow-y: auto; + background-color: #fff; + box-shadow: 0 2px 4px rgba(0, 0, 0, .12) +} + +.layui-table-cell, .layui-table-tool-panel li { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap +} + +.layui-table-tool-panel li { + padding: 0 10px; + line-height: 30px; + -webkit-transition: .5s all; + transition: .5s all +} + +.layui-menu li, .layui-menu-body-title a:hover, .layui-menu-body-title > .layui-icon:hover { + transition: all .3s +} + +.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] { + width: 100%; + padding-left: 28px +} + +.layui-table-tool-panel li:hover { + background-color: #F6F6F6 +} + +.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] i { + position: absolute; + left: 0; + top: 0 +} + +.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] span { + padding: 0 +} + +.layui-table-tool .layui-table-tool-self .layui-table-tool-panel { + left: auto; + right: -1px +} + +.layui-table-col-set { + position: absolute; + right: 0; + top: 0; + width: 20px; + height: 100%; + border-width: 0 0 0 1px; + background-color: #fff +} + +.layui-table-sort { + width: 10px; + height: 20px; + margin-left: 5px; + cursor: pointer !important +} + +.layui-table-sort .layui-edge { + position: absolute; + left: 5px; + border-width: 5px +} + +.layui-table-sort .layui-table-sort-asc { + top: 3px; + border-top: none; + border-bottom-style: solid; + border-bottom-color: #b2b2b2 +} + +.layui-table-sort .layui-table-sort-asc:hover { + border-bottom-color: #666 +} + +.layui-table-sort .layui-table-sort-desc { + bottom: 5px; + border-bottom: none; + border-top-style: solid; + border-top-color: #b2b2b2 +} + +.layui-table-sort .layui-table-sort-desc:hover { + border-top-color: #666 +} + +.layui-table-sort[lay-sort=asc] .layui-table-sort-asc { + border-bottom-color: #000 +} + +.layui-table-sort[lay-sort=desc] .layui-table-sort-desc { + border-top-color: #000 +} + +.layui-table-cell { + height: 28px; + line-height: 28px; + padding: 0 15px; + position: relative; + box-sizing: border-box +} + +.layui-table-cell .layui-form-checkbox[lay-skin=primary] { + top: -1px; + padding: 0 +} + +.layui-table-cell .layui-table-link { + color: #01AAED +} + +.laytable-cell-checkbox, .laytable-cell-numbers, .laytable-cell-radio, .laytable-cell-space { + padding: 0; + text-align: center +} + +.layui-table-body { + position: relative; + overflow: auto; + margin-right: -1px; + margin-bottom: -1px +} + +.layui-table-body .layui-none { + line-height: 26px; + padding: 15px; + text-align: center; + color: #999 +} + +.layui-table-fixed { + position: absolute; + left: 0; + top: 0; + z-index: 101 +} + +.layui-table-fixed .layui-table-body { + overflow: hidden +} + +.layui-table-fixed-l { + box-shadow: 0 -1px 8px rgba(0, 0, 0, .08) +} + +.layui-table-fixed-r { + left: auto; + right: -1px; + border-width: 0 0 0 1px; + box-shadow: -1px 0 8px rgba(0, 0, 0, .08) +} + +.layui-table-fixed-r .layui-table-header { + position: relative; + overflow: visible +} + +.layui-table-mend { + position: absolute; + right: -49px; + top: 0; + height: 100%; + width: 50px +} + +.layui-table-tool { + position: relative; + z-index: 890; + width: 100%; + min-height: 50px; + line-height: 30px; + padding: 10px 15px; + border-width: 0 0 1px +} + +.layui-table-tool .layui-btn-container { + margin-bottom: -10px +} + +.layui-table-page, .layui-table-total { + border-width: 1px 0 0; + margin-bottom: -1px; + overflow: hidden +} + +.layui-table-page { + position: relative; + width: 100%; + padding: 7px 7px 0; + height: 41px; + font-size: 12px; + white-space: nowrap +} + +.layui-table-page > div { + height: 26px +} + +.layui-table-page .layui-laypage { + margin: 0 +} + +.layui-table-page .layui-laypage a, .layui-table-page .layui-laypage span { + height: 26px; + line-height: 26px; + margin-bottom: 10px; + border: none; + background: 0 0 +} + +.layui-table-page .layui-laypage a, .layui-table-page .layui-laypage span.layui-laypage-curr { + padding: 0 12px +} + +.layui-table-page .layui-laypage span { + margin-left: 0; + padding: 0 +} + +.layui-table-page .layui-laypage .layui-laypage-prev { + margin-left: -7px !important +} + +.layui-table-page .layui-laypage .layui-laypage-curr .layui-laypage-em { + left: 0; + top: 0; + padding: 0 +} + +.layui-table-page .layui-laypage button, .layui-table-page .layui-laypage input { + height: 26px; + line-height: 26px +} + +.layui-table-page .layui-laypage input { + width: 40px +} + +.layui-table-page .layui-laypage button { + padding: 0 10px +} + +.layui-table-page select { + height: 18px +} + +.layui-table-patch .layui-table-cell { + padding: 0; + width: 30px +} + +.layui-table-edit { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + padding: 0 14px 1px; + border-radius: 0; + box-shadow: 1px 1px 20px rgba(0, 0, 0, .15) +} + +.layui-table-edit:focus { + border-color: #5FB878 !important +} + +select.layui-table-edit { + padding: 0 0 0 10px; + border-color: #d2d2d2 +} + +.layui-table-view .layui-form-checkbox, .layui-table-view .layui-form-radio, .layui-table-view .layui-form-switch { + top: 0; + margin: 0; + box-sizing: content-box +} + +.layui-colorpicker-alpha-slider, .layui-colorpicker-side-slider, .layui-menu, .layui-menu *, .layui-nav { + box-sizing: border-box +} + +.layui-table-view .layui-form-checkbox { + top: -1px; + height: 26px; + line-height: 26px +} + +.layui-table-view .layui-form-checkbox i { + height: 26px +} + +.layui-table-grid .layui-table-cell { + overflow: visible +} + +.layui-table-grid-down { + position: absolute; + top: 0; + right: 0; + width: 26px; + height: 100%; + padding: 5px 0; + border-width: 0 0 0 1px; + text-align: center; + background-color: #fff; + color: #999; + cursor: pointer +} + +.layui-table-grid-down .layui-icon { + position: absolute; + top: 50%; + left: 50%; + margin: -8px 0 0 -8px +} + +.layui-table-grid-down:hover { + background-color: #fbfbfb +} + +body .layui-table-tips .layui-layer-content { + background: 0 0; + padding: 0; + box-shadow: 0 1px 6px rgba(0, 0, 0, .12) +} + +.layui-table-tips-main { + margin: -44px 0 0 -1px; + max-height: 150px; + padding: 8px 15px; + font-size: 14px; + overflow-y: scroll; + background-color: #fff; + color: #666 +} + +.layui-table-tips-c { + position: absolute; + right: -3px; + top: -13px; + width: 20px; + height: 20px; + padding: 3px; + cursor: pointer; + background-color: #666; + border-radius: 50%; + color: #fff +} + +.layui-table-tips-c:hover { + background-color: #777 +} + +.layui-table-tips-c:before { + position: relative; + right: -2px +} + +.layui-upload-file { + display: none !important; + opacity: .01; + filter: Alpha(opacity=1) +} + +.layui-upload-drag, .layui-upload-form, .layui-upload-wrap { + display: inline-block +} + +.layui-upload-list { + margin: 10px 0 +} + +.layui-upload-choose { + padding: 0 10px; + color: #999 +} + +.layui-upload-drag { + position: relative; + padding: 30px; + border: 1px dashed #e2e2e2; + background-color: #fff; + text-align: center; + cursor: pointer; + color: #999 +} + +.layui-upload-drag .layui-icon { + font-size: 50px; + color: #009688 +} + +.layui-upload-drag[lay-over] { + border-color: #009688 +} + +.layui-upload-iframe { + position: absolute; + width: 0; + height: 0; + border: 0; + visibility: hidden +} + +.layui-upload-wrap { + position: relative; + vertical-align: middle +} + +.layui-upload-wrap .layui-upload-file { + display: block !important; + position: absolute; + left: 0; + top: 0; + z-index: 10; + font-size: 100px; + width: 100%; + height: 100%; + opacity: .01; + filter: Alpha(opacity=1); + cursor: pointer +} + +.layui-menu { + position: relative; + margin: 5px 0; + background-color: #fff +} + +.layui-menu li, .layui-menu-body-title a { + padding: 5px 15px +} + +.layui-menu li { + position: relative; + margin: 1px 0; + width: calc(100% + 1px); + line-height: 22px; + color: rgba(0, 0, 0, .8); + font-size: 14px; + white-space: nowrap; + cursor: pointer +} + +.layui-menu li:hover { + background-color: #F6F6F6 +} + +.layui-menu-item-parent:hover > .layui-menu-body-panel { + display: block; + animation-name: layui-fadein; + animation-duration: .3s; + animation-fill-mode: both; + animation-delay: .2s +} + +.layui-menu-item-group .layui-menu-body-title, .layui-menu-item-parent .layui-menu-body-title { + padding-right: 25px +} + +.layui-menu .layui-menu-item-divider:hover, .layui-menu .layui-menu-item-group:hover, .layui-menu .layui-menu-item-none:hover { + background: 0 0; + cursor: default +} + +.layui-menu .layui-menu-item-group > ul { + margin: 5px 0 -5px +} + +.layui-menu .layui-menu-item-group > .layui-menu-body-title { + color: rgba(0, 0, 0, .35); + user-select: none +} + +.layui-menu .layui-menu-item-none { + color: rgba(0, 0, 0, .35); + cursor: default; + text-align: center +} + +.layui-menu .layui-menu-item-divider { + margin: 5px 0; + padding: 0; + height: 0; + line-height: 0; + border-bottom: 1px solid #eee; + overflow: hidden +} + +.layui-menu .layui-menu-item-down:hover, .layui-menu .layui-menu-item-up:hover { + cursor: pointer +} + +.layui-menu .layui-menu-item-up > .layui-menu-body-title { + color: rgba(0, 0, 0, .8) +} + +.layui-menu .layui-menu-item-up > ul { + visibility: hidden; + height: 0; + overflow: hidden +} + +.layui-menu .layui-menu-item-down:hover > .layui-menu-body-title > .layui-icon, .layui-menu .layui-menu-item-up > .layui-menu-body-title:hover > .layui-icon { + color: rgba(0, 0, 0, 1) +} + +.layui-menu .layui-menu-item-down > ul { + visibility: visible; + height: auto +} + +.layui-breadcrumb, .layui-tree-btnGroup { + visibility: hidden +} + +.layui-menu .layui-menu-item-checked, .layui-menu .layui-menu-item-checked2 { + background-color: #F6F6F6 !important; + color: #5FB878 +} + +.layui-menu .layui-menu-item-checked a, .layui-menu .layui-menu-item-checked2 a { + color: #5FB878 +} + +.layui-menu .layui-menu-item-checked:after { + position: absolute; + right: 0; + top: 0; + bottom: 0; + border-right: 3px solid #5FB878; + content: "" +} + +.layui-menu-body-title { + position: relative; + overflow: hidden; + text-overflow: ellipsis +} + +.layui-menu-body-title a { + display: block; + margin: -5px -15px; + color: rgba(0, 0, 0, .8) +} + +.layui-menu-body-title > .layui-icon { + position: absolute; + right: 0; + top: 0; + font-size: 14px +} + +.layui-menu-body-title > .layui-icon-right { + right: -1px +} + +.layui-menu-body-panel { + display: none; + position: absolute; + top: -7px; + left: 100%; + z-index: 1000; + margin-left: 13px; + padding: 5px 0 +} + +.layui-transfer-active, .layui-transfer-box { + display: inline-block; + vertical-align: middle +} + +.layui-menu-body-panel:before { + content: ""; + position: absolute; + width: 20px; + left: -16px; + top: 0; + bottom: 0 +} + +.layui-menu-body-panel-left { + left: auto; + right: 100%; + margin: 0 13px +} + +.layui-menu-body-panel-left:before { + left: auto; + right: -16px +} + +.layui-menu-lg li { + line-height: 32px +} + +.layui-menu-lg .layui-menu-body-title a:hover, .layui-menu-lg li:hover { + background: 0 0; + color: #5FB878 +} + +.layui-menu-lg li .layui-menu-body-panel { + margin-left: 14px +} + +.layui-menu-lg li .layui-menu-body-panel-left { + margin: 0 15px +} + +.layui-dropdown { + position: absolute; + left: -999999px; + top: -999999px; + z-index: 66666666; + margin: 5px 0; + min-width: 100px +} + +.layui-dropdown:before { + content: ""; + position: absolute; + width: 100%; + height: 6px; + left: 0; + top: -6px +} + +.layui-transfer-box, .layui-transfer-header, .layui-transfer-search { + border-width: 0; + border-style: solid; + border-color: #eee +} + +.layui-transfer-box { + position: relative; + border-width: 1px; + width: 200px; + height: 360px; + border-radius: 2px; + background-color: #fff +} + +.layui-transfer-box .layui-form-checkbox { + width: 100%; + margin: 0 !important +} + +.layui-transfer-header { + height: 38px; + line-height: 38px; + padding: 0 10px; + border-bottom-width: 1px +} + +.layui-transfer-search { + position: relative; + padding: 10px; + border-bottom-width: 1px +} + +.layui-transfer-search .layui-input { + height: 32px; + padding-left: 30px; + font-size: 12px +} + +.layui-transfer-search .layui-icon-search { + position: absolute; + left: 20px; + top: 50%; + margin-top: -8px; + color: #666 +} + +.layui-transfer-active { + margin: 0 15px +} + +.layui-transfer-active .layui-btn { + display: block; + margin: 0; + padding: 0 15px; + background-color: #5FB878; + border-color: #5FB878; + color: #fff +} + +.layui-transfer-active .layui-btn-disabled { + background-color: #FBFBFB; + border-color: #eee; + color: #d2d2d2 +} + +.layui-transfer-active .layui-btn:first-child { + margin-bottom: 15px +} + +.layui-transfer-active .layui-btn .layui-icon { + margin: 0; + font-size: 14px !important +} + +.layui-transfer-data { + padding: 5px 0; + overflow: auto +} + +.layui-transfer-data li { + height: 32px; + line-height: 32px; + padding: 0 10px +} + +.layui-transfer-data li:hover { + background-color: #F6F6F6; + transition: .5s all +} + +.layui-transfer-data .layui-none { + padding: 15px 10px; + text-align: center; + color: #999 +} + +.layui-nav { + position: relative; + padding: 0 20px; + background-color: #393D49; + color: #fff; + border-radius: 2px; + font-size: 0 +} + +.layui-nav * { + font-size: 14px +} + +.layui-nav .layui-nav-item { + position: relative; + display: inline-block; + *display: inline; + *zoom: 1; + vertical-align: middle; + line-height: 60px +} + +.layui-nav .layui-nav-item a { + display: block; + padding: 0 20px; + color: #fff; + color: rgba(255, 255, 255, .7); + transition: all .3s; + -webkit-transition: all .3s +} + +.layui-nav .layui-this:after, .layui-nav-bar, .layui-nav-tree .layui-nav-itemed:after { + position: absolute; + left: 0; + top: 0; + width: 0; + height: 5px; + background-color: #5FB878; + transition: all .2s; + -webkit-transition: all .2s +} + +.layui-nav-bar { + z-index: 1000 +} + +.layui-nav .layui-nav-item a:hover, .layui-nav .layui-this a { + color: #fff +} + +.layui-nav .layui-this:after { + content: ""; + top: auto; + bottom: 0; + width: 100% +} + +.layui-nav-img { + width: 30px; + height: 30px; + margin-right: 10px; + border-radius: 50% +} + +.layui-nav .layui-nav-more { + content: ""; + width: 0; + height: 0; + border-style: solid dashed dashed; + border-color: #fff transparent transparent; + overflow: hidden; + cursor: pointer; + transition: all .2s; + -webkit-transition: all .2s; + position: absolute; + top: 50%; + right: 3px; + margin-top: -4px; + border-width: 6px; + border-top-color: rgba(255, 255, 255, .7) +} + +.layui-nav .layui-nav-mored, .layui-nav-itemed > a .layui-nav-more { + margin-top: -9px; + border-style: dashed dashed solid; + border-color: transparent transparent #fff +} + +.layui-nav-child { + display: none; + position: absolute; + left: 0; + top: 65px; + min-width: 100%; + line-height: 36px; + padding: 5px 0; + box-shadow: 0 2px 4px rgba(0, 0, 0, .12); + border: 1px solid #d2d2d2; + background-color: #fff; + z-index: 100; + border-radius: 2px; + white-space: nowrap +} + +.layui-nav .layui-nav-child a { + color: #333 +} + +.layui-nav .layui-nav-child a:hover { + background-color: #F6F6F6; + color: #5FB878 +} + +.layui-nav-child dd { + position: relative +} + +.layui-nav .layui-nav-child dd.layui-this a, .layui-nav-child dd.layui-this { + background-color: #5FB878; + color: #fff +} + +.layui-nav-child dd.layui-this:after { + display: none +} + +.layui-nav-tree { + width: 200px; + padding: 0 +} + +.layui-nav-tree .layui-nav-item { + display: block; + width: 100%; + line-height: 45px +} + +.layui-nav-tree .layui-nav-item a { + position: relative; + height: 45px; + line-height: 45px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap +} + +.layui-nav-tree .layui-nav-item a:hover { + background-color: #4E5465 +} + +.layui-nav-tree .layui-nav-bar { + width: 5px; + height: 0; + background-color: #009688 +} + +.layui-nav-tree .layui-nav-child dd.layui-this, .layui-nav-tree .layui-nav-child dd.layui-this a, .layui-nav-tree .layui-this, .layui-nav-tree .layui-this > a, .layui-nav-tree .layui-this > a:hover { + background-color: #009688; + color: #fff +} + +.layui-nav-tree .layui-this:after { + display: none +} + +.layui-nav-itemed > a, .layui-nav-tree .layui-nav-title a, .layui-nav-tree .layui-nav-title a:hover { + color: #fff !important +} + +.layui-nav-tree .layui-nav-child { + position: relative; + z-index: 0; + top: 0; + border: none; + box-shadow: none +} + +.layui-nav-tree .layui-nav-child a { + height: 40px; + line-height: 40px; + color: #fff; + color: rgba(255, 255, 255, .7) +} + +.layui-nav-tree .layui-nav-child, .layui-nav-tree .layui-nav-child a:hover { + background: 0 0; + color: #fff +} + +.layui-nav-tree .layui-nav-more { + right: 10px +} + +.layui-nav-itemed > .layui-nav-child { + display: block; + padding: 0; + background-color: rgba(0, 0, 0, .3) !important +} + +.layui-nav-itemed > .layui-nav-child > .layui-this > .layui-nav-child { + display: block +} + +.layui-nav-side { + position: fixed; + top: 0; + bottom: 0; + left: 0; + overflow-x: hidden; + z-index: 999 +} + +.layui-bg-blue .layui-nav-bar, .layui-bg-blue .layui-nav-itemed:after, .layui-bg-blue .layui-this:after { + background-color: #93D1FF +} + +.layui-bg-blue .layui-nav-child dd.layui-this { + background-color: #1E9FFF +} + +.layui-bg-blue .layui-nav-itemed > a, .layui-nav-tree.layui-bg-blue .layui-nav-title a, .layui-nav-tree.layui-bg-blue .layui-nav-title a:hover { + background-color: #007DDB !important +} + +.layui-breadcrumb { + font-size: 0 +} + +.layui-breadcrumb > * { + font-size: 14px +} + +.layui-breadcrumb a { + color: #999 !important +} + +.layui-breadcrumb a:hover { + color: #5FB878 !important +} + +.layui-breadcrumb a cite { + color: #666; + font-style: normal +} + +.layui-breadcrumb span[lay-separator] { + margin: 0 10px; + color: #999 +} + +.layui-tab { + margin: 10px 0; + text-align: left !important +} + +.layui-tab[overflow] > .layui-tab-title { + overflow: hidden +} + +.layui-tab-title { + position: relative; + left: 0; + height: 40px; + white-space: nowrap; + font-size: 0; + border-bottom-width: 1px; + border-bottom-style: solid; + transition: all .2s; + -webkit-transition: all .2s +} + +.layui-tab-title li { + display: inline-block; + *display: inline; + *zoom: 1; + vertical-align: middle; + font-size: 14px; + transition: all .2s; + -webkit-transition: all .2s; + position: relative; + line-height: 40px; + min-width: 65px; + padding: 0 15px; + text-align: center; + cursor: pointer +} + +.layui-tab-title li a { + display: block +} + +.layui-tab-title .layui-this { + color: #000 +} + +.layui-tab-title .layui-this:after { + position: absolute; + left: 0; + top: 0; + content: ""; + width: 100%; + height: 41px; + border-width: 1px; + border-style: solid; + border-bottom-color: #fff; + border-radius: 2px 2px 0 0; + box-sizing: border-box; + pointer-events: none +} + +.layui-tab-bar { + position: absolute; + right: 0; + top: 0; + z-index: 10; + width: 30px; + height: 39px; + line-height: 39px; + border-width: 1px; + border-style: solid; + border-radius: 2px; + text-align: center; + background-color: #fff; + cursor: pointer +} + +.layui-tab-bar .layui-icon { + position: relative; + display: inline-block; + top: 3px; + transition: all .3s; + -webkit-transition: all .3s +} + +.layui-tab-item { + display: none +} + +.layui-tab-more { + padding-right: 30px; + height: auto !important; + white-space: normal !important +} + +.layui-tab-more li.layui-this:after { + border-bottom-color: #eee; + border-radius: 2px +} + +.layui-tab-more .layui-tab-bar .layui-icon { + top: -2px; + top: 3px \9; + -webkit-transform: rotate(180deg); + transform: rotate(180deg) +} + +:root .layui-tab-more .layui-tab-bar .layui-icon { + top: -2px \0/ IE9 +} + +.layui-tab-content { + padding: 15px 0 +} + +.layui-tab-title li .layui-tab-close { + position: relative; + display: inline-block; + width: 18px; + height: 18px; + line-height: 20px; + margin-left: 8px; + top: 1px; + text-align: center; + font-size: 14px; + color: #c2c2c2; + transition: all .2s; + -webkit-transition: all .2s +} + +.layui-tab-title li .layui-tab-close:hover { + border-radius: 2px; + background-color: #FF5722; + color: #fff +} + +.layui-tab-brief > .layui-tab-title .layui-this { + color: #009688 +} + +.layui-tab-brief > .layui-tab-more li.layui-this:after, .layui-tab-brief > .layui-tab-title .layui-this:after { + border: none; + border-radius: 0; + border-bottom: 2px solid #5FB878 +} + +.layui-tab-brief[overflow] > .layui-tab-title .layui-this:after { + top: -1px +} + +.layui-tab-card { + border-width: 1px; + border-style: solid; + border-radius: 2px; + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1) +} + +.layui-tab-card > .layui-tab-title { + background-color: #FAFAFA +} + +.layui-tab-card > .layui-tab-title li { + margin-right: -1px; + margin-left: -1px +} + +.layui-tab-card > .layui-tab-title .layui-this { + background-color: #fff +} + +.layui-tab-card > .layui-tab-title .layui-this:after { + border-top: none; + border-width: 1px; + border-bottom-color: #fff +} + +.layui-tab-card > .layui-tab-title .layui-tab-bar { + height: 40px; + line-height: 40px; + border-radius: 0; + border-top: none; + border-right: none +} + +.layui-tab-card > .layui-tab-more .layui-this { + background: 0 0; + color: #5FB878 +} + +.layui-tab-card > .layui-tab-more .layui-this:after { + border: none +} + +.layui-timeline { + padding-left: 5px +} + +.layui-timeline-item { + position: relative; + padding-bottom: 20px +} + +.layui-timeline-axis { + position: absolute; + left: -5px; + top: 0; + z-index: 10; + width: 20px; + height: 20px; + line-height: 20px; + background-color: #fff; + color: #5FB878; + border-radius: 50%; + text-align: center; + cursor: pointer +} + +.layui-timeline-axis:hover { + color: #FF5722 +} + +.layui-timeline-item:before { + content: ""; + position: absolute; + left: 5px; + top: 0; + z-index: 0; + width: 1px; + height: 100% +} + +.layui-timeline-item:first-child:before { + display: block +} + +.layui-timeline-item:last-child:before { + display: none +} + +.layui-timeline-content { + padding-left: 25px +} + +.layui-timeline-title { + position: relative; + margin-bottom: 10px; + line-height: 22px +} + +.layui-badge, .layui-badge-dot, .layui-badge-rim { + position: relative; + display: inline-block; + padding: 0 6px; + font-size: 12px; + text-align: center; + background-color: #FF5722; + color: #fff; + border-radius: 2px +} + +.layui-badge { + height: 18px; + line-height: 18px +} + +.layui-badge-dot { + width: 8px; + height: 8px; + padding: 0; + border-radius: 50% +} + +.layui-badge-rim { + height: 18px; + line-height: 18px; + border-width: 1px; + border-style: solid; + background-color: #fff; + color: #666 +} + +.layui-btn .layui-badge, .layui-btn .layui-badge-dot { + margin-left: 5px +} + +.layui-nav .layui-badge, .layui-nav .layui-badge-dot { + position: absolute; + top: 50%; + margin: -5px 6px 0 +} + +.layui-nav .layui-badge { + margin-top: -10px +} + +.layui-tab-title .layui-badge, .layui-tab-title .layui-badge-dot { + left: 5px; + top: -2px +} + +.layui-carousel { + position: relative; + left: 0; + top: 0; + background-color: #f8f8f8 +} + +.layui-carousel > [carousel-item] { + position: relative; + width: 100%; + height: 100%; + overflow: hidden +} + +.layui-carousel > [carousel-item]:before { + position: absolute; + content: '\e63d'; + left: 50%; + top: 50%; + width: 100px; + line-height: 20px; + margin: -10px 0 0 -50px; + text-align: center; + color: #c2c2c2; + font-family: layui-icon !important; + font-size: 30px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale +} + +.layui-carousel > [carousel-item] > * { + display: none; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: #f8f8f8; + transition-duration: .3s; + -webkit-transition-duration: .3s +} + +.layui-carousel-updown > * { + -webkit-transition: .3s ease-in-out up; + transition: .3s ease-in-out up +} + +.layui-carousel-arrow { + display: none \9; + opacity: 0; + position: absolute; + left: 10px; + top: 50%; + margin-top: -18px; + width: 36px; + height: 36px; + line-height: 36px; + text-align: center; + font-size: 20px; + border: 0; + border-radius: 50%; + background-color: rgba(0, 0, 0, .2); + color: #fff; + -webkit-transition-duration: .3s; + transition-duration: .3s; + cursor: pointer +} + +.layui-carousel-arrow[lay-type=add] { + left: auto !important; + right: 10px +} + +.layui-carousel:hover .layui-carousel-arrow[lay-type=add], .layui-carousel[lay-arrow=always] .layui-carousel-arrow[lay-type=add] { + right: 20px +} + +.layui-carousel[lay-arrow=always] .layui-carousel-arrow { + opacity: 1; + left: 20px +} + +.layui-carousel[lay-arrow=none] .layui-carousel-arrow { + display: none +} + +.layui-carousel-arrow:hover, .layui-carousel-ind ul:hover { + background-color: rgba(0, 0, 0, .35) +} + +.layui-carousel:hover .layui-carousel-arrow { + display: block \9; + opacity: 1; + left: 20px +} + +.layui-carousel-ind { + position: relative; + top: -35px; + width: 100%; + line-height: 0 !important; + text-align: center; + font-size: 0 +} + +.layui-carousel[lay-indicator=outside] { + margin-bottom: 30px +} + +.layui-carousel[lay-indicator=outside] .layui-carousel-ind { + top: 10px +} + +.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul { + background-color: rgba(0, 0, 0, .5) +} + +.layui-carousel[lay-indicator=none] .layui-carousel-ind { + display: none +} + +.layui-carousel-ind ul { + display: inline-block; + padding: 5px; + background-color: rgba(0, 0, 0, .2); + border-radius: 10px; + -webkit-transition-duration: .3s; + transition-duration: .3s +} + +.layui-carousel-ind li { + display: inline-block; + width: 10px; + height: 10px; + margin: 0 3px; + font-size: 14px; + background-color: #eee; + background-color: rgba(255, 255, 255, .5); + border-radius: 50%; + cursor: pointer; + -webkit-transition-duration: .3s; + transition-duration: .3s +} + +.layui-carousel-ind li:hover { + background-color: rgba(255, 255, 255, .7) +} + +.layui-carousel-ind li.layui-this { + background-color: #fff +} + +.layui-carousel > [carousel-item] > .layui-carousel-next, .layui-carousel > [carousel-item] > .layui-carousel-prev, .layui-carousel > [carousel-item] > .layui-this { + display: block +} + +.layui-carousel > [carousel-item] > .layui-this { + left: 0 +} + +.layui-carousel > [carousel-item] > .layui-carousel-prev { + left: -100% +} + +.layui-carousel > [carousel-item] > .layui-carousel-next { + left: 100% +} + +.layui-carousel > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel > [carousel-item] > .layui-carousel-prev.layui-carousel-right { + left: 0 +} + +.layui-carousel > [carousel-item] > .layui-this.layui-carousel-left { + left: -100% +} + +.layui-carousel > [carousel-item] > .layui-this.layui-carousel-right { + left: 100% +} + +.layui-carousel[lay-anim=updown] .layui-carousel-arrow { + left: 50% !important; + top: 20px; + margin: 0 0 0 -18px +} + +.layui-carousel[lay-anim=updown] > [carousel-item] > *, .layui-carousel[lay-anim=fade] > [carousel-item] > * { + left: 0 !important +} + +.layui-carousel[lay-anim=updown] .layui-carousel-arrow[lay-type=add] { + top: auto !important; + bottom: 20px +} + +.layui-carousel[lay-anim=updown] .layui-carousel-ind { + position: absolute; + top: 50%; + right: 20px; + width: auto; + height: auto +} + +.layui-carousel[lay-anim=updown] .layui-carousel-ind ul { + padding: 3px 5px +} + +.layui-carousel[lay-anim=updown] .layui-carousel-ind li { + display: block; + margin: 6px 0 +} + +.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this { + top: 0 +} + +.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-prev { + top: -100% +} + +.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-next { + top: 100% +} + +.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel[lay-anim=updown] > [carousel-item] > .layui-carousel-prev.layui-carousel-right { + top: 0 +} + +.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this.layui-carousel-left { + top: -100% +} + +.layui-carousel[lay-anim=updown] > [carousel-item] > .layui-this.layui-carousel-right { + top: 100% +} + +.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-next, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-prev { + opacity: 0 +} + +.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-next.layui-carousel-left, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-carousel-prev.layui-carousel-right { + opacity: 1 +} + +.layui-carousel[lay-anim=fade] > [carousel-item] > .layui-this.layui-carousel-left, .layui-carousel[lay-anim=fade] > [carousel-item] > .layui-this.layui-carousel-right { + opacity: 0 +} + +.layui-fixbar { + position: fixed; + right: 15px; + bottom: 15px; + z-index: 999999 +} + +.layui-fixbar li { + width: 50px; + height: 50px; + line-height: 50px; + margin-bottom: 1px; + text-align: center; + cursor: pointer; + font-size: 30px; + background-color: #9F9F9F; + color: #fff; + border-radius: 2px; + opacity: .95 +} + +.layui-fixbar li:hover { + opacity: .85 +} + +.layui-fixbar li:active { + opacity: 1 +} + +.layui-fixbar .layui-fixbar-top { + display: none; + font-size: 40px +} + +body .layui-util-face { + border: none; + background: 0 0 +} + +body .layui-util-face .layui-layer-content { + padding: 0; + background-color: #fff; + color: #666; + box-shadow: none +} + +.layui-util-face .layui-layer-TipsG { + display: none +} + +.layui-util-face ul { + position: relative; + width: 372px; + padding: 10px; + border: 1px solid #D9D9D9; + background-color: #fff; + box-shadow: 0 0 20px rgba(0, 0, 0, .2) +} + +.layui-util-face ul li { + cursor: pointer; + float: left; + border: 1px solid #e8e8e8; + height: 22px; + width: 26px; + overflow: hidden; + margin: -1px 0 0 -1px; + padding: 4px 2px; + text-align: center +} + +.layui-util-face ul li:hover { + position: relative; + z-index: 2; + border: 1px solid #eb7350; + background: #fff9ec +} + +.layui-code { + position: relative; + margin: 10px 0; + padding: 15px; + line-height: 20px; + border: 1px solid #eee; + border-left-width: 6px; + background-color: #FAFAFA; + color: #333; + font-family: Courier New; + font-size: 12px +} + +.layui-rate, .layui-rate * { + display: inline-block; + vertical-align: middle +} + +.layui-rate { + padding: 10px 5px 10px 0; + font-size: 0 +} + +.layui-rate li i.layui-icon { + font-size: 20px; + color: #FFB800; + margin-right: 5px; + transition: all .3s; + -webkit-transition: all .3s +} + +.layui-rate li i:hover { + cursor: pointer; + transform: scale(1.12); + -webkit-transform: scale(1.12) +} + +.layui-rate[readonly] li i:hover { + cursor: default; + transform: scale(1) +} + +.layui-colorpicker { + width: 26px; + height: 26px; + border: 1px solid #eee; + padding: 5px; + border-radius: 2px; + line-height: 24px; + display: inline-block; + cursor: pointer; + transition: all .3s; + -webkit-transition: all .3s +} + +.layui-colorpicker:hover { + border-color: #d2d2d2 +} + +.layui-colorpicker.layui-colorpicker-lg { + width: 34px; + height: 34px; + line-height: 32px +} + +.layui-colorpicker.layui-colorpicker-sm { + width: 24px; + height: 24px; + line-height: 22px +} + +.layui-colorpicker.layui-colorpicker-xs { + width: 22px; + height: 22px; + line-height: 20px +} + +.layui-colorpicker-trigger-bgcolor { + display: block; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); + border-radius: 2px +} + +.layui-colorpicker-trigger-span { + display: block; + height: 100%; + box-sizing: border-box; + border: 1px solid rgba(0, 0, 0, .15); + border-radius: 2px; + text-align: center +} + +.layui-colorpicker-trigger-i { + display: inline-block; + color: #FFF; + font-size: 12px +} + +.layui-colorpicker-trigger-i.layui-icon-close { + color: #999 +} + +.layui-colorpicker-main { + position: absolute; + z-index: 66666666; + width: 280px; + padding: 7px; + background: #FFF; + border: 1px solid #d2d2d2; + border-radius: 2px; + box-shadow: 0 2px 4px rgba(0, 0, 0, .12) +} + +.layui-colorpicker-main-wrapper { + height: 180px; + position: relative +} + +.layui-colorpicker-basis { + width: 260px; + height: 100%; + position: relative +} + +.layui-colorpicker-basis-white { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background: linear-gradient(90deg, #FFF, hsla(0, 0%, 100%, 0)) +} + +.layui-colorpicker-basis-black { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background: linear-gradient(0deg, #000, transparent) +} + +.layui-colorpicker-basis-cursor { + width: 10px; + height: 10px; + border: 1px solid #FFF; + border-radius: 50%; + position: absolute; + top: -3px; + right: -3px; + cursor: pointer +} + +.layui-colorpicker-side { + position: absolute; + top: 0; + right: 0; + width: 12px; + height: 100%; + background: linear-gradient(red, #FF0, #0F0, #0FF, #00F, #F0F, red) +} + +.layui-colorpicker-side-slider { + width: 100%; + height: 5px; + box-shadow: 0 0 1px #888; + background: #FFF; + border-radius: 1px; + border: 1px solid #f0f0f0; + cursor: pointer; + position: absolute; + left: 0 +} + +.layui-colorpicker-main-alpha { + display: none; + height: 12px; + margin-top: 7px; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==) +} + +.layui-colorpicker-alpha-bgcolor { + height: 100%; + position: relative +} + +.layui-colorpicker-alpha-slider { + width: 5px; + height: 100%; + box-shadow: 0 0 1px #888; + background: #FFF; + border-radius: 1px; + border: 1px solid #f0f0f0; + cursor: pointer; + position: absolute; + top: 0 +} + +.layui-colorpicker-main-pre { + padding-top: 7px; + font-size: 0 +} + +.layui-colorpicker-pre { + width: 20px; + height: 20px; + border-radius: 2px; + display: inline-block; + margin-left: 6px; + margin-bottom: 7px; + cursor: pointer +} + +.layui-colorpicker-pre:nth-child(11n+1) { + margin-left: 0 +} + +.layui-colorpicker-pre-isalpha { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==) +} + +.layui-colorpicker-pre.layui-this { + box-shadow: 0 0 3px 2px rgba(0, 0, 0, .15) +} + +.layui-colorpicker-pre > div { + height: 100%; + border-radius: 2px +} + +.layui-colorpicker-main-input { + text-align: right; + padding-top: 7px +} + +.layui-colorpicker-main-input .layui-btn-container .layui-btn { + margin: 0 0 0 10px +} + +.layui-colorpicker-main-input div.layui-inline { + float: left; + margin-right: 10px; + font-size: 14px +} + +.layui-colorpicker-main-input input.layui-input { + width: 150px; + height: 30px; + color: #666 +} + +.layui-slider { + height: 4px; + background: #eee; + border-radius: 3px; + position: relative; + cursor: pointer +} + +.layui-slider-bar { + border-radius: 3px; + position: absolute; + height: 100% +} + +.layui-slider-step { + position: absolute; + top: 0; + width: 4px; + height: 4px; + border-radius: 50%; + background: #FFF; + -webkit-transform: translateX(-50%); + transform: translateX(-50%) +} + +.layui-slider-wrap { + width: 36px; + height: 36px; + position: absolute; + top: -16px; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + z-index: 10; + text-align: center +} + +.layui-slider-wrap-btn { + width: 12px; + height: 12px; + border-radius: 50%; + background: #FFF; + display: inline-block; + vertical-align: middle; + cursor: pointer; + transition: .3s +} + +.layui-slider-wrap:after { + content: ""; + height: 100%; + display: inline-block; + vertical-align: middle +} + +.layui-slider-wrap-btn.layui-slider-hover, .layui-slider-wrap-btn:hover { + transform: scale(1.2) +} + +.layui-slider-wrap-btn.layui-disabled:hover { + transform: scale(1) !important +} + +.layui-slider-tips { + position: absolute; + top: -42px; + z-index: 66666666; + white-space: nowrap; + display: none; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + color: #FFF; + background: #000; + border-radius: 3px; + height: 25px; + line-height: 25px; + padding: 0 10px +} + +.layui-slider-tips:after { + content: ""; + position: absolute; + bottom: -12px; + left: 50%; + margin-left: -6px; + width: 0; + height: 0; + border-width: 6px; + border-style: solid; + border-color: #000 transparent transparent +} + +.layui-slider-input { + width: 70px; + height: 32px; + border: 1px solid #eee; + border-radius: 3px; + font-size: 16px; + line-height: 32px; + position: absolute; + right: 0; + top: -14px +} + +.layui-slider-input-btn { + position: absolute; + top: 0; + right: 0; + width: 20px; + height: 100%; + border-left: 1px solid #eee +} + +.layui-slider-input-btn i { + cursor: pointer; + position: absolute; + right: 0; + bottom: 0; + width: 20px; + height: 50%; + font-size: 12px; + line-height: 16px; + text-align: center; + color: #999 +} + +.layui-slider-input-btn i:first-child { + top: 0; + border-bottom: 1px solid #eee +} + +.layui-slider-input-txt { + height: 100%; + font-size: 14px +} + +.layui-slider-input-txt input { + height: 100%; + border: none +} + +.layui-slider-input-btn i:hover { + color: #009688 +} + +.layui-slider-vertical { + width: 4px; + margin-left: 33px +} + +.layui-slider-vertical .layui-slider-bar { + width: 4px +} + +.layui-slider-vertical .layui-slider-step { + top: auto; + left: 0; + -webkit-transform: translateY(50%); + transform: translateY(50%) +} + +.layui-slider-vertical .layui-slider-wrap { + top: auto; + left: -16px; + -webkit-transform: translateY(50%); + transform: translateY(50%) +} + +.layui-slider-vertical .layui-slider-tips { + top: auto; + left: 2px +} + +@media \0screen { + .layui-slider-wrap-btn { + margin-left: -20px + } + + .layui-slider-vertical .layui-slider-wrap-btn { + margin-left: 0; + margin-bottom: -20px + } + + .layui-slider-vertical .layui-slider-tips { + margin-left: -8px + } + + .layui-slider > span { + margin-left: 8px + } +} + +.layui-tree { + line-height: 22px +} + +.layui-tree .layui-form-checkbox { + margin: 0 !important +} + +.layui-tree-set { + width: 100%; + position: relative +} + +.layui-tree-pack { + display: none; + padding-left: 20px; + position: relative +} + +.layui-tree-iconClick, .layui-tree-main { + display: inline-block; + vertical-align: middle +} + +.layui-tree-line .layui-tree-pack { + padding-left: 27px +} + +.layui-tree-line .layui-tree-set .layui-tree-set:after { + content: ""; + position: absolute; + top: 14px; + left: -9px; + width: 17px; + height: 0; + border-top: 1px dotted #c0c4cc +} + +.layui-tree-entry { + position: relative; + padding: 3px 0; + height: 20px; + white-space: nowrap +} + +.layui-tree-entry:hover { + background-color: #eee +} + +.layui-tree-line .layui-tree-entry:hover { + background-color: rgba(0, 0, 0, 0) +} + +.layui-tree-line .layui-tree-entry:hover .layui-tree-txt { + color: #999; + text-decoration: underline; + transition: .3s +} + +.layui-tree-main { + cursor: pointer; + padding-right: 10px +} + +.layui-tree-line .layui-tree-set:before { + content: ""; + position: absolute; + top: 0; + left: -9px; + width: 0; + height: 100%; + border-left: 1px dotted #c0c4cc +} + +.layui-tree-line .layui-tree-set.layui-tree-setLineShort:before { + height: 13px +} + +.layui-tree-line .layui-tree-set.layui-tree-setHide:before { + height: 0 +} + +.layui-tree-iconClick { + position: relative; + height: 20px; + line-height: 20px; + margin: 0 10px; + color: #c0c4cc +} + +.layui-tree-icon { + height: 12px; + line-height: 12px; + width: 12px; + text-align: center; + border: 1px solid #c0c4cc +} + +.layui-tree-iconClick .layui-icon { + font-size: 18px +} + +.layui-tree-icon .layui-icon { + font-size: 12px; + color: #666 +} + +.layui-tree-iconArrow { + padding: 0 5px +} + +.layui-tree-iconArrow:after { + content: ""; + position: absolute; + left: 4px; + top: 3px; + z-index: 100; + width: 0; + height: 0; + border-width: 5px; + border-style: solid; + border-color: transparent transparent transparent #c0c4cc; + transition: .5s +} + +.layui-tree-btnGroup, .layui-tree-editInput { + position: relative; + vertical-align: middle; + display: inline-block +} + +.layui-tree-spread > .layui-tree-entry > .layui-tree-iconClick > .layui-tree-iconArrow:after { + transform: rotate(90deg) translate(3px, 4px) +} + +.layui-tree-txt { + display: inline-block; + vertical-align: middle; + color: #555 +} + +.layui-tree-search { + margin-bottom: 15px; + color: #666 +} + +.layui-tree-btnGroup .layui-icon { + display: inline-block; + vertical-align: middle; + padding: 0 2px; + cursor: pointer +} + +.layui-tree-btnGroup .layui-icon:hover { + color: #999; + transition: .3s +} + +.layui-tree-entry:hover .layui-tree-btnGroup { + visibility: visible +} + +.layui-tree-editInput { + height: 20px; + line-height: 20px; + padding: 0 3px; + border: none; + background-color: rgba(0, 0, 0, .05) +} + +.layui-tree-emptyText { + text-align: center; + color: #999 +} + +.layui-anim { + -webkit-animation-duration: .2s; + -webkit-animation-fill-mode: both; + animation-duration: .2s; + animation-fill-mode: both +} + +.layui-anim.layui-icon { + display: inline-block +} + +.layui-anim-loop { + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite +} + +.layui-trans, .layui-trans a { + transition: all .2s; + -webkit-transition: all .2s +} + +@-webkit-keyframes layui-rotate { + from { + -webkit-transform: rotate(0) + } + to { + -webkit-transform: rotate(360deg) + } +} + +@keyframes layui-rotate { + from { + transform: rotate(0) + } + to { + transform: rotate(360deg) + } +} + +.layui-anim-rotate { + -webkit-animation-name: layui-rotate; + animation-name: layui-rotate; + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-timing-function: linear; + animation-timing-function: linear +} + +@-webkit-keyframes layui-up { + from { + -webkit-transform: translate3d(0, 100%, 0); + opacity: .3 + } + to { + -webkit-transform: translate3d(0, 0, 0); + opacity: 1 + } +} + +@keyframes layui-up { + from { + transform: translate3d(0, 100%, 0); + opacity: .3 + } + to { + transform: translate3d(0, 0, 0); + opacity: 1 + } +} + +.layui-anim-up { + -webkit-animation-name: layui-up; + animation-name: layui-up +} + +@-webkit-keyframes layui-upbit { + from { + -webkit-transform: translate3d(0, 15px, 0); + opacity: .3 + } + to { + -webkit-transform: translate3d(0, 0, 0); + opacity: 1 + } +} + +@keyframes layui-upbit { + from { + transform: translate3d(0, 15px, 0); + opacity: .3 + } + to { + transform: translate3d(0, 0, 0); + opacity: 1 + } +} + +.layui-anim-upbit { + -webkit-animation-name: layui-upbit; + animation-name: layui-upbit +} + +@keyframes layui-down { + 0% { + opacity: .3; + transform: translate3d(0, -100%, 0) + } + 100% { + opacity: 1; + transform: translate3d(0, 0, 0) + } +} + +.layui-anim-down { + animation-name: layui-down +} + +@keyframes layui-downbit { + 0% { + opacity: .3; + transform: translate3d(0, -5px, 0) + } + 100% { + opacity: 1; + transform: translate3d(0, 0, 0) + } +} + +.layui-anim-downbit { + animation-name: layui-downbit +} + +@-webkit-keyframes layui-scale { + 0% { + opacity: .3; + -webkit-transform: scale(.5) + } + 100% { + opacity: 1; + -webkit-transform: scale(1) + } +} + +@keyframes layui-scale { + 0% { + opacity: .3; + -ms-transform: scale(.5); + transform: scale(.5) + } + 100% { + opacity: 1; + -ms-transform: scale(1); + transform: scale(1) + } +} + +.layui-anim-scale { + -webkit-animation-name: layui-scale; + animation-name: layui-scale +} + +@-webkit-keyframes layui-scale-spring { + 0% { + opacity: .5; + -webkit-transform: scale(.5) + } + 80% { + opacity: .8; + -webkit-transform: scale(1.1) + } + 100% { + opacity: 1; + -webkit-transform: scale(1) + } +} + +@keyframes layui-scale-spring { + 0% { + opacity: .5; + transform: scale(.5) + } + 80% { + opacity: .8; + transform: scale(1.1) + } + 100% { + opacity: 1; + transform: scale(1) + } +} + +.layui-anim-scaleSpring { + -webkit-animation-name: layui-scale-spring; + animation-name: layui-scale-spring +} + +@keyframes layui-scalesmall { + 0% { + opacity: .3; + transform: scale(1.5) + } + 100% { + opacity: 1; + transform: scale(1) + } +} + +.layui-anim-scalesmall { + animation-name: layui-scalesmall +} + +@keyframes layui-scalesmall-spring { + 0% { + opacity: .3; + transform: scale(1.5) + } + 80% { + opacity: .8; + transform: scale(.9) + } + 100% { + opacity: 1; + transform: scale(1) + } +} + +.layui-anim-scalesmall-spring { + animation-name: layui-scalesmall-spring +} + +@-webkit-keyframes layui-fadein { + 0% { + opacity: 0 + } + 100% { + opacity: 1 + } +} + +@keyframes layui-fadein { + 0% { + opacity: 0 + } + 100% { + opacity: 1 + } +} + +.layui-anim-fadein { + -webkit-animation-name: layui-fadein; + animation-name: layui-fadein +} + +@-webkit-keyframes layui-fadeout { + 0% { + opacity: 1 + } + 100% { + opacity: 0 + } +} + +@keyframes layui-fadeout { + 0% { + opacity: 1 + } + 100% { + opacity: 0 + } +} + +.layui-anim-fadeout { + -webkit-animation-name: layui-fadeout; + animation-name: layui-fadeout +} diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/code.css b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/code.css new file mode 100644 index 0000000..0fee0c5 --- /dev/null +++ b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/code.css @@ -0,0 +1 @@ +html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#FAFAFA;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 10px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view .layui-code-ol li:first-child{padding-top:10px}.layui-code-view .layui-code-ol li:last-child{padding-bottom:10px}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}.layui-code-demo .layui-code{visibility:visible!important;margin:-15px;border-top:none;border-right:none;border-bottom:none}.layui-code-demo .layui-tab-content{padding:15px;border-top:none} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/laydate/default/laydate.css b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/laydate/default/laydate.css new file mode 100644 index 0000000..9f3064b --- /dev/null +++ b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/laydate/default/laydate.css @@ -0,0 +1 @@ +.laydate-set-ym,.layui-laydate,.layui-laydate *,.layui-laydate-list{box-sizing:border-box}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate{position:absolute;z-index:66666666;margin:5px 0;border-radius:2px;font-size:14px;-webkit-animation-duration:.2s;animation-duration:.2s;-webkit-animation-fill-mode:both;animation-fill-mode:both;animation-name:laydate-downbit}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}@keyframes laydate-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon,.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.laydate-set-ym span,.layui-laydate-header i{padding:0 5px;cursor:pointer}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;color:#999;font-size:18px}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:5px;text-align:center}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;height:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px 20px}.layui-laydate-footer span{margin-right:15px;display:inline-block;cursor:pointer;font-size:12px}.layui-laydate-footer span:hover{color:#5FB878}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{height:26px;line-height:26px;margin:0 0 0 -1px;padding:0 10px;border:1px solid #C9C9C9;background-color:#fff;white-space:nowrap;vertical-align:top;border-radius:2px}.layui-laydate-list>li,.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle}.layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;background-color:#fff}.layui-laydate-list>li{position:relative;width:33.3%;height:36px;line-height:36px;margin:3px 0;text-align:center;cursor:pointer}.laydate-month-list>li{width:25%;margin:17px 0}.laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.laydate-time-list p{position:relative;top:-4px;line-height:29px}.laydate-time-list ol{height:181px;overflow:hidden}.laydate-time-list>li:hover ol{overflow-y:auto}.laydate-time-list ol li{width:130%;padding-left:33px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px}.layui-laydate-range{width:546px}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid #e2e2e2}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#666}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#5FB878}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{font-weight:400;color:#333}.layui-laydate-content td{color:#666}.layui-laydate-content td.laydate-selected{background-color:#B5FFF8}.laydate-selected:hover{background-color:#00F7DE!important}.layui-laydate-content td:hover,.layui-laydate-list li:hover{background-color:#eee;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.laydate-selected.laydate-day-next,.laydate-selected.laydate-day-prev{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#FF5722}.laydate-day-mark::after{background-color:#5FB878}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#5FB878}.layui-laydate .layui-this{background-color:#009688!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#009688}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead,.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-selected,.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#009688!important}.laydate-theme-grid .laydate-selected.laydate-day-next,.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/icon-ext.png b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/icon-ext.png new file mode 100644 index 0000000..bbbb669 Binary files /dev/null and b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/icon-ext.png differ diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/icon.png b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/icon.png new file mode 100644 index 0000000..3e17da8 Binary files /dev/null and b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/icon.png differ diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/layer.css b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/layer.css new file mode 100644 index 0000000..ef1db1d --- /dev/null +++ b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/layer.css @@ -0,0 +1 @@ +.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:50px;line-height:50px;border-bottom:1px solid #F0F0F0;font-size:14px;color:#333;overflow:hidden;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:17px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1E9FFF;background-color:#1E9FFF;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:300px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#E9E7E7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:260px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:300px;padding:0 20px;text-align:center;overflow:hidden;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:51px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}} \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-0.gif b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-0.gif new file mode 100644 index 0000000..6f3c953 Binary files /dev/null and b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-0.gif differ diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-1.gif b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-1.gif new file mode 100644 index 0000000..db3a483 Binary files /dev/null and b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-1.gif differ diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-2.gif b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-2.gif new file mode 100644 index 0000000..5bb90fd Binary files /dev/null and b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/css/modules/layer/default/loading-2.gif differ diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.eot b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.eot new file mode 100644 index 0000000..622d7ec Binary files /dev/null and b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.eot differ diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.svg b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.svg new file mode 100644 index 0000000..999ca1f --- /dev/null +++ b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.svg @@ -0,0 +1,554 @@ + + + + + +Created by iconfont + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.ttf b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.ttf new file mode 100644 index 0000000..06e30f9 Binary files /dev/null and b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.ttf differ diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.woff b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.woff new file mode 100644 index 0000000..66a1783 Binary files /dev/null and b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.woff differ diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.woff2 b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.woff2 new file mode 100644 index 0000000..47e9980 Binary files /dev/null and b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/font/iconfont.woff2 differ diff --git a/ss-admin/src/main/resources/static/lib/layui-v2.6.3/layui.js b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/layui.js new file mode 100644 index 0000000..f74410d --- /dev/null +++ b/ss-admin/src/main/resources/static/lib/layui-v2.6.3/layui.js @@ -0,0 +1,5 @@ +/** layui v2.6.3 | Released under the MIT license */ + ;!function(t){"use strict";var e=document,n={modules:{},status:{},timeout:10,event:{}},r=function(){this.v="2.6.3"},o=function(){var t=e.currentScript?e.currentScript.src:function(){for(var t,n=e.scripts,r=n.length-1,o=r;o>0;o--)if("interactive"===n[o].readyState){t=n[o].src;break}return t||n[r].src}();return t.substring(0,t.lastIndexOf("/")+1)}(),a=function(e,n){n=n||"log",t.console&&console[n]&&console[n]("layui error hint: "+e)},i="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),u=n.builtin={lay:"lay",layer:"layer",laydate:"laydate",laypage:"laypage",laytpl:"laytpl",layedit:"layedit",form:"form",upload:"upload",dropdown:"dropdown",transfer:"transfer",tree:"tree",table:"table",element:"element",rate:"rate",colorpicker:"colorpicker",slider:"slider",carousel:"carousel",flow:"flow",util:"util",code:"code",jquery:"jquery",all:"all","layui.all":"layui.all"};r.prototype.cache=n,r.prototype.define=function(t,e){var r=this,o="function"==typeof t,a=function(){var t=function(t,e){layui[t]=e,n.status[t]=!0};return"function"==typeof e&&e(function(r,o){t(r,o),n.callback[r]=function(){e(t)}}),this};return o&&(e=t,t=[]),r.use(t,a),r},r.prototype.use=function(t,r,l){function c(t,e){var r="PLaySTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/;("load"===t.type||r.test((t.currentTarget||t.srcElement).readyState))&&(n.modules[d]=e,y.removeChild(m),function o(){return++v>1e3*n.timeout/4?a(d+" is not a valid module","error"):void(n.status[d]?s():setTimeout(o,4))}())}function s(){l.push(layui[d]),t.length>1?p.use(t.slice(1),r,l):"function"==typeof r&&function(){return layui.jquery&&"function"==typeof layui.jquery?layui.jquery(function(){r.apply(layui,l)}):void r.apply(layui,l)}()}var p=this,f=n.dir=n.dir?n.dir:o,y=e.getElementsByTagName("head")[0];t=function(){return"string"==typeof t?[t]:"function"==typeof t?(r=t,["all"]):t}();var d=t[0],v=0;if(l=l||[],n.host=n.host||(f.match(/\/\/([\s\S]+?)\//)||["//"+location.host+"/"])[0],0===t.length||layui["layui.all"]&&u[d])return s(),p;var h=(u[d]?f+"modules/":/^\{\/\}/.test(p.modules[d])?"":n.base||"")+(p.modules[d]||d)+".js";if(h=h.replace(/^\{\/\}/,""),!n.modules[d]&&layui[d]&&(n.modules[d]=h),n.modules[d])!function g(){return++v>1e3*n.timeout/4?a(d+" is not a valid module","error"):void("string"==typeof n.modules[d]&&n.status[d]?s():setTimeout(g,4))}();else{var m=e.createElement("script");m.async=!0,m.charset="utf-8",m.src=h+function(){var t=n.version===!0?n.v||(new Date).getTime():n.version||"";return t?"?v="+t:""}(),y.appendChild(m),!m.attachEvent||m.attachEvent.toString&&m.attachEvent.toString().indexOf("[native code")<0||i?m.addEventListener("load",function(t){c(t,h)},!1):m.attachEvent("onreadystatechange",function(t){c(t,h)}),n.modules[d]=h}return p},r.prototype.getStyle=function(e,n){var r=e.currentStyle?e.currentStyle:t.getComputedStyle(e,null);return r[r.getPropertyValue?"getPropertyValue":"getAttribute"](n)},r.prototype.link=function(t,r,o){var i=this,u=e.createElement("link"),l=e.getElementsByTagName("head")[0];"string"==typeof r&&(o=r);var c=(o||t).replace(/\.|\//g,""),s=u.id="layuicss-"+c,p=0;return u.rel="stylesheet",u.href=t+(n.debug?"?v="+(new Date).getTime():""),u.media="all",e.getElementById(s)||l.appendChild(u),"function"!=typeof r?i:(function f(){return++p>1e3*n.timeout/100?a(t+" timeout"):void(1989===parseInt(i.getStyle(e.getElementById(s),"width"))?function(){r()}():setTimeout(f,100))}(),i)},n.callback={},r.prototype.factory=function(t){if(layui[t])return"function"==typeof n.callback[t]?n.callback[t]:null},r.prototype.addcss=function(t,e,r){return layui.link(n.dir+"css/"+t,e,r)},r.prototype.img=function(t,e,n){var r=new Image;return r.src=t,r.complete?e(r):(r.onload=function(){r.onload=null,"function"==typeof e&&e(r)},void(r.onerror=function(t){r.onerror=null,"function"==typeof n&&n(t)}))},r.prototype.config=function(t){t=t||{};for(var e in t)n[e]=t[e];return this},r.prototype.modules=function(){var t={};for(var e in u)t[e]=u[e];return t}(),r.prototype.extend=function(t){var e=this;t=t||{};for(var n in t)e[n]||e.modules[n]?a(n+" Module already exists","error"):e.modules[n]=t[n];return e},r.prototype.router=function(t){var e=this,t=t||location.hash,n={path:[],search:{},hash:(t.match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(t)?(t=t.replace(/^#\//,""),n.href="/"+t,t=t.replace(/([^#])(#.*$)/,"$1").split("/")||[],e.each(t,function(t,e){/^\w+=/.test(e)?function(){e=e.split("="),n.search[e[0]]=e[1]}():n.path.push(e)}),n):n},r.prototype.url=function(t){var e=this,n={pathname:function(){var e=t?function(){var e=(t.match(/\.[^.]+?\/.+/)||[])[0]||"";return e.replace(/^[^\/]+/,"").replace(/\?.+/,"")}():location.pathname;return e.replace(/^\//,"").split("/")}(),search:function(){var n={},r=(t?function(){var e=(t.match(/\?.+/)||[])[0]||"";return e.replace(/\#.+/,"")}():location.search).replace(/^\?+/,"").split("&");return e.each(r,function(t,e){var r=e.indexOf("="),o=function(){return r<0?e.substr(0,e.length):0!==r&&e.substr(0,r)}();o&&(n[o]=r>0?e.substr(r+1):null)}),n}(),hash:e.router(function(){return t?(t.match(/#.+/)||[])[0]||"":location.hash}())};return n},r.prototype.data=function(e,n,r){if(e=e||"layui",r=r||localStorage,t.JSON&&t.JSON.parse){if(null===n)return delete r[e];n="object"==typeof n?n:{key:n};try{var o=JSON.parse(r[e])}catch(a){var o={}}return"value"in n&&(o[n.key]=n.value),n.remove&&delete o[n.key],r[e]=JSON.stringify(o),n.key?o[n.key]:o}},r.prototype.sessionData=function(t,e){return this.data(t,e,sessionStorage)},r.prototype.device=function(e){var n=navigator.userAgent.toLowerCase(),r=function(t){var e=new RegExp(t+"/([^\\s\\_\\-]+)");return t=(n.match(e)||[])[1],t||!1},o={os:function(){return/windows/.test(n)?"windows":/linux/.test(n)?"linux":/iphone|ipod|ipad|ios/.test(n)?"ios":/mac/.test(n)?"mac":void 0}(),ie:function(){return!!(t.ActiveXObject||"ActiveXObject"in t)&&((n.match(/msie\s(\d+)/)||[])[1]||"11")}(),weixin:r("micromessenger")};return e&&!o[e]&&(o[e]=r(e)),o.android=/android/.test(n),o.ios="ios"===o.os,o.mobile=!(!o.android&&!o.ios),o},r.prototype.hint=function(){return{error:a}},r.prototype.each=function(t,e){var n,r=this;if("function"!=typeof e)return r;if(t=t||[],t.constructor===Object){for(n in t)if(e.call(t[n],n,t[n]))break}else for(n=0;na?1:o0;o--)if("interactive"===n[o].readyState){t=n[o].src;break}return t||n[r].src}();return t.substring(0,t.lastIndexOf("/")+1)},n.stope=function(t){t=t||window.event,t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},n.each=function(t,e){var n,r=this;if("function"!=typeof e)return r;if(t=t||[],t.constructor===Object){for(n in t)if(e.call(t[n],n,t[n]))break}else for(n=0;n80?window.console&&console.error(u+".css: Invalid"):void(1989===parseInt(n.getStyle(e.getElementById(a),"width"))?r():setTimeout(l,100))}()},n.hasScrollbar=function(){return e.body.scrollHeight>(window.innerHeight||e.documentElement.clientHeight)},n.position=function(t,r,o){if(r){o=o||{},t!==e&&t!==n("body")[0]||(o.clickType="right");var i="right"===o.clickType?function(){var t=o.e||window.event||{};return{left:t.clientX,top:t.clientY,right:t.clientX,bottom:t.clientY}}():t.getBoundingClientRect(),c=r.offsetWidth,u=r.offsetHeight,a=function(t){return t=t?"scrollLeft":"scrollTop",e.body[t]|e.documentElement[t]},s=function(t){return e.documentElement[t?"clientWidth":"clientHeight"]},l=5,f=i.left,p=i.bottom;f+c+l>s("width")&&(f=s("width")-c-l),p+u+l>s()&&(i.top>u+l?p=i.top-u-2*l:"right"===o.clickType&&(p=s()-u-2*l,p<0&&(p=0)));var h=o.position;if(h&&(r.style.position=h),r.style.left=f+("fixed"===h?0:a(1))+"px",r.style.top=p+("fixed"===h?0:a())+"px",!n.hasScrollbar()){var d=r.getBoundingClientRect();!o.SYSTEM_RELOAD&&d.bottom+l>s()&&(o.SYSTEM_RELOAD=!0,setTimeout(function(){n.position(t,r,o)},50))}}},n.options=function(t,e){var r=n(t),o=e||"lay-options";try{return new Function("return "+(r.attr(o)||"{}"))()}catch(i){return hint.error("parseerror:"+i,"error"),{}}},n.isTopElem=function(t){var r=[e,n("body")[0]],o=!1;return n.each(r,function(e,n){if(n===t)return o=!0}),o},r.addStr=function(t,e){return t=t.replace(/\s+/," "),e=e.replace(/\s+/," ").split(" "),n.each(e,function(e,n){new RegExp("\\b"+n+"\\b").test(t)||(t=t+" "+n)}),t.replace(/^\s|\s$/,"")},r.removeStr=function(t,e){return t=t.replace(/\s+/," "),e=e.replace(/\s+/," ").split(" "),n.each(e,function(e,n){var r=new RegExp("\\b"+n+"\\b");r.test(t)&&(t=t.replace(r,""))}),t.replace(/\s+/," ").replace(/^\s|\s$/,"")},r.prototype.find=function(t){var e=this,r=0,o=[],i="object"==typeof t;return this.each(function(n,c){for(var u=i?[t]:c.querySelectorAll(t||null);r0)return r[0].style[t]}():r.each(function(r,i){"object"==typeof t?n.each(t,function(t,e){i.style[t]=o(e)}):i.style[t]=o(e)})},r.prototype.width=function(t){var e=this;return void 0===t?function(){if(e.length>0)return e[0].offsetWidth}():e.each(function(n,r){e.css("width",t)})},r.prototype.height=function(t){var e=this;return void 0===t?function(){if(e.length>0)return e[0].offsetHeight}():e.each(function(n,r){e.css("height",t)})},r.prototype.attr=function(t,e){var n=this;return void 0===e?function(){if(n.length>0)return n[0].getAttribute(t)}():n.each(function(n,r){r.setAttribute(t,e)})},r.prototype.removeAttr=function(t){return this.each(function(e,n){n.removeAttribute(t)})},r.prototype.html=function(t){return this.each(function(e,n){n.innerHTML=t})},r.prototype.val=function(t){return this.each(function(e,n){n.value=t})},r.prototype.append=function(t){return this.each(function(e,n){"object"==typeof t?n.appendChild(t):n.innerHTML=n.innerHTML+t})},r.prototype.remove=function(t){return this.each(function(e,n){t?n.removeChild(t):n.parentNode.removeChild(n)})},r.prototype.on=function(t,e){return this.each(function(n,r){r.attachEvent?r.attachEvent("on"+t,function(t){t.target=t.srcElement,e.call(r,t)}):r.addEventListener(t,e,!1)})},r.prototype.off=function(t,e){return this.each(function(n,r){r.detachEvent?r.detachEvent("on"+t,e):r.removeEventListener(t,e,!1)})},window.lay=n,window.layui&&layui.define&&layui.define(function(e){e(t,n)})}();layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},c={exp:function(e){return new RegExp(e,"g")},query:function(e,c,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return n((c||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var c="Laytpl Error: ";return"object"==typeof console&&console.error(c+e+"\n"+(r||"")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n("^"+r.open+"#",""),l=n(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(n(r.open+"#"),r.open+"# ").replace(n(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(n(r.open+"!(.+?)!"+r.close),function(e){return e=e.replace(n("^"+r.open+"!"),"").replace(n("!"+r.close),"").replace(n(r.open+"|"+r.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(c.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(c.query(1),function(e){var c='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(n(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),c='"+_escape_('),c+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error("no data")};var o=function(e){return"string"!=typeof e?c.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v="1.2.0",e("laytpl",o)});layui.define(function(e){"use strict";var a=document,t="getElementById",n="getElementsByTagName",i="laypage",r="layui-disabled",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups="groups"in a?0|a.groups:5;a.layout="object"==typeof a.layout?a.layout:["prev","page","next"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits="object"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev="prev"in a?a.prev:"上一页",a.next="next"in a?a.next:"下一页";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?''+a.prev+"":""}(),page:function(){var e=[];if(a.count<1)return"";n>1&&a.first!==!1&&0!==t&&e.push(''+(a.first||1)+"");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r2&&e.push('');r<=u;r++)r===a.curr?e.push('"+r+""):e.push(''+r+"");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1…'),0!==t&&e.push(''+(a.last||a.pages)+"")),e.join("")}(),next:function(){return a.next?''+a.next+"":""}(),count:'共 '+a.count+" 条",limit:function(){var e=['"}(),refresh:['','',""].join(""),skip:function(){return['到第','','页',""].join("")}()};return['
            ',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join("")}(),"
            "].join("")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n]("button")[0],l=e[n]("input")[0],p=e[n]("select")[0],c=function(){var e=0|l.value.replace(/\s|\D/g,"");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;oi.pages||(i.curr=e,t.render())});p&&s.on(p,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,"click",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n]("input")[0];t&&s.on(t,"keyup",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\D/.test(n)&&(this.value=n.replace(/\D/,"")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t]("layui-laypage-"+i.index);n.jump(s),i.hash&&!e&&(location.hash="!"+i.hash+"="+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent("on"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)});!function(e){"use strict";var t=e.layui&&layui.define,a={getPath:e.lay&&lay.getPath?lay.getPath():"",link:function(t,a,l){n.path&&e.lay&&lay.link&&lay.link(n.path+t,a,l)}},n={v:"5.2.1",config:{},index:e.laydate&&e.laydate.v?1e5:0,path:a.getPath,set:function(e){var t=this;return t.config=lay.extend({},t.config,e),t},ready:function(e){var l="laydate",i="",r=(t?"modules/laydate/":"theme/")+"default/laydate.css?v="+n.v+i;return t?layui.addcss(r,e,l):a.link(r,e,l),this}},l=function(){var e=this;return{hint:function(t){e.hint.call(e,t)},config:e.config}},i="laydate",r=".layui-laydate",o="layui-this",s="laydate-disabled",y=[100,2e5],d="layui-laydate-static",m="layui-laydate-list",c="laydate-selected",u="layui-laydate-hint",h="layui-laydate-footer",f=".laydate-btns-confirm",p="laydate-time-text",g=".laydate-btns-time",v=function(e){var t=this;t.index=++n.index,t.config=lay.extend({},t.config,n.config,e),n.ready(function(){t.init()})};v.isLeapYear=function(e){return e%4===0&&e%100!==0||e%400===0},v.prototype.config={type:"date",range:!1,format:"yyyy-MM-dd",value:null,isInitValue:!0,min:"1900-1-1",max:"2099-12-31",trigger:"click",show:!1,showBottom:!0,btns:["clear","now","confirm"],lang:"cn",theme:"default",position:null,calendar:!1,mark:{},zIndex:null,done:null,change:null},v.prototype.lang=function(){var e=this,t=e.config,a={cn:{weeks:["日","一","二","三","四","五","六"],time:["时","分","秒"],timeTips:"选择时间",startTime:"开始时间",endTime:"结束时间",dateTips:"返回日期",month:["一","二","三","四","五","六","七","八","九","十","十一","十二"],tools:{confirm:"确定",clear:"清空",now:"现在"},timeout:"结束时间不能早于开始时间
            请重新选择",invalidDate:"不在有效日期或时间范围内",formatError:["日期格式不合法
            必须遵循下述格式:
            ","
            已为你重置"]},en:{weeks:["Su","Mo","Tu","We","Th","Fr","Sa"],time:["Hours","Minutes","Seconds"],timeTips:"Select Time",startTime:"Start Time",endTime:"End Time",dateTips:"Select Date",month:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],tools:{confirm:"Confirm",clear:"Clear",now:"Now"},timeout:"End time cannot be less than start Time
            Please re-select",invalidDate:"Invalid date",formatError:["The date format error
            Must be followed:
            ","
            It has been reset"]}};return a[t.lang]||a.cn},v.prototype.init=function(){var t=this,a=t.config,n="yyyy|y|MM|M|dd|d|HH|H|mm|m|ss|s",l="static"===a.position,i={year:"yyyy",month:"yyyy-MM",date:"yyyy-MM-dd",time:"HH:mm:ss",datetime:"yyyy-MM-dd HH:mm:ss"};a.elem=lay(a.elem),a.eventElem=lay(a.eventElem),a.elem[0]&&(a.range===!0&&(a.range="-"),i[a.type]||(e.console&&console.error&&console.error("laydate type error:'"+a.type+"' is not supported"),a.type="date"),a.format===i.date&&(a.format=i[a.type]||i.date),t.format=a.format.match(new RegExp(n+"|.","g"))||[],t.EXP_IF="",t.EXP_SPLIT="",lay.each(t.format,function(e,a){var l=new RegExp(n).test(a)?"\\d{"+function(){return new RegExp(n).test(t.format[0===e?e+1:e-1]||"")?/^yyyy|y$/.test(a)?4:a.length:/^yyyy$/.test(a)?"1,4":/^y$/.test(a)?"1,308":"1,2"}()+"}":"\\"+a;t.EXP_IF=t.EXP_IF+l,t.EXP_SPLIT=t.EXP_SPLIT+"("+l+")"}),t.EXP_IF=new RegExp("^"+(a.range?t.EXP_IF+"\\s\\"+a.range+"\\s"+t.EXP_IF:t.EXP_IF)+"$"),t.EXP_SPLIT=new RegExp("^"+t.EXP_SPLIT+"$",""),t.isInput(a.elem[0])||"focus"===a.trigger&&(a.trigger="click"),a.elem.attr("lay-key")||(a.elem.attr("lay-key",t.index),a.eventElem.attr("lay-key",t.index)),a.mark=lay.extend({},a.calendar&&"cn"===a.lang?{"0-1-1":"元旦","0-2-14":"情人","0-3-8":"妇女","0-3-12":"植树","0-4-1":"愚人","0-5-1":"劳动","0-5-4":"青年","0-6-1":"儿童","0-9-10":"教师","0-9-18":"国耻","0-10-1":"国庆","0-12-25":"圣诞"}:{},a.mark),lay.each(["min","max"],function(e,t){var n=[],l=[];if("number"==typeof a[t]){var i=a[t],r=(new Date).getTime(),o=864e5,s=new Date(i?i0)return!0;var n=lay.elem("div",{"class":"layui-laydate-header"}),l=[function(){var e=lay.elem("i",{"class":"layui-icon laydate-icon laydate-prev-y"});return e.innerHTML="",e}(),function(){var e=lay.elem("i",{"class":"layui-icon laydate-icon laydate-prev-m"});return e.innerHTML="",e}(),function(){var e=lay.elem("div",{"class":"laydate-set-ym"}),t=lay.elem("span"),a=lay.elem("span");return e.appendChild(t),e.appendChild(a),e}(),function(){var e=lay.elem("i",{"class":"layui-icon laydate-icon laydate-next-m"});return e.innerHTML="",e}(),function(){var e=lay.elem("i",{"class":"layui-icon laydate-icon laydate-next-y"});return e.innerHTML="",e}()],y=lay.elem("div",{"class":"layui-laydate-content"}),d=lay.elem("table"),m=lay.elem("thead"),c=lay.elem("tr");lay.each(l,function(e,t){n.appendChild(t)}),m.appendChild(c),lay.each(new Array(6),function(e){var t=d.insertRow(0);lay.each(new Array(7),function(n){if(0===e){var l=lay.elem("th");l.innerHTML=a.weeks[n],c.appendChild(l)}t.insertCell(n)})}),d.insertBefore(m,d.children[0]),y.appendChild(d),i[e]=lay.elem("div",{"class":"layui-laydate-main laydate-main-list-"+e}),i[e].appendChild(n),i[e].appendChild(y),r.push(l),o.push(y),s.push(d)}),lay(y).html(function(){var e=[],l=[];return"datetime"===t.type&&e.push(''+a.timeTips+""),lay.each(t.btns,function(e,i){var r=a.tools[i]||"btn";t.range&&"now"===i||(n&&"clear"===i&&(r="cn"===t.lang?"重置":"Reset"),l.push(''+r+""))}),e.push('"),e.join("")}()),lay.each(i,function(e,t){l.appendChild(t)}),t.showBottom&&l.appendChild(y),/^#/.test(t.theme)){var m=lay.elem("style"),c=["#{{id}} .layui-laydate-header{background-color:{{theme}};}","#{{id}} .layui-this{background-color:{{theme}} !important;}"].join("").replace(/{{id}}/g,e.elemID).replace(/{{theme}}/g,t.theme);"styleSheet"in m?(m.setAttribute("type","text/css"),m.styleSheet.cssText=c):m.innerHTML=c,lay(l).addClass("laydate-theme-molv"),l.appendChild(m)}e.remove(v.thisElemDate),n?t.elem.append(l):(document.body.appendChild(l),e.position()),e.checkDate().calendar(null,0,"init"),e.changeEvent(),v.thisElemDate=e.elemID,"function"==typeof t.ready&&t.ready(lay.extend({},t.dateTime,{month:t.dateTime.month+1}))},v.prototype.remove=function(e){var t=this,a=(t.config,lay("#"+(e||t.elemID)));return a[0]?(a.hasClass(d)||t.checkDate(function(){a.remove(),delete t.endDate}),t):t},v.prototype.position=function(){var e=this,t=e.config;return lay.position(e.bindElem||t.elem[0],e.elem,{position:t.position}),e},v.prototype.hint=function(e){var t=this,a=(t.config,lay.elem("div",{"class":u}));t.elem&&(a.innerHTML=e||"",lay(t.elem).find("."+u).remove(),t.elem.appendChild(a),clearTimeout(t.hinTimer),t.hinTimer=setTimeout(function(){lay(t.elem).find("."+u).remove()},3e3))},v.prototype.getAsYM=function(e,t,a){return a?t--:t++,t<0&&(t=11,e--),t>11&&(t=0,e++),[e,t]},v.prototype.systemDate=function(e){var t=e||new Date;return{year:t.getFullYear(),month:t.getMonth(),date:t.getDate(),hours:e?e.getHours():0,minutes:e?e.getMinutes():0,seconds:e?e.getSeconds():0}},v.prototype.checkDate=function(e){var t,a,l=this,i=(new Date,l.config),r=l.lang(),o=i.dateTime=i.dateTime||l.systemDate(),s=l.bindElem||i.elem[0],d=(l.isInput(s)?"val":"html",l.isInput(s)?s.value:"static"===i.position?"":s.innerHTML),m=function(e){e.year>y[1]&&(e.year=y[1],a=!0),e.month>11&&(e.month=11,a=!0),e.hours>23&&(e.hours=0,a=!0),e.minutes>59&&(e.minutes=0,e.hours++,a=!0),e.seconds>59&&(e.seconds=0,e.minutes++,a=!0),t=n.getEndDate(e.month+1,e.year),e.date>t&&(e.date=t,a=!0)},c=function(e,t,n){var r=["startTime","endTime"];t=(t.match(l.EXP_SPLIT)||[]).slice(1),n=n||0,i.range&&(l[r[n]]=l[r[n]]||{}),lay.each(l.format,function(o,s){var d=parseFloat(t[o]);t[o].length'+a+""),n},v.prototype.limit=function(e,t,a,n){var l,i=this,r=i.config,o={},y=r[a>41?"endDate":"dateTime"],d=lay.extend({},y,t||{});return lay.each({now:d,min:r.min,max:r.max},function(e,t){o[e]=i.newDate(lay.extend({year:t.year,month:t.month,date:t.date},function(){var e={};return lay.each(n,function(a,n){e[n]=t[n]}),e}())).getTime()}),l=o.nowo.max,e&&e[l?"addClass":"removeClass"](s),l},v.prototype.thisDateTime=function(e){var t=this,a=t.config;return e?t.endDate:a.dateTime},v.prototype.calendar=function(e,t,a){var l,i,r,s=this,d=s.config,t=t?1:0,m=e||s.thisDateTime(t),c=new Date,u=s.lang(),h="date"!==d.type&&"datetime"!==d.type,p=lay(s.table[t]).find("td"),g=lay(s.elemHeader[t][2]).find("span");return m.yeary[1]&&(m.year=y[1],s.hint(u.invalidDate)),s.firstDate||(s.firstDate=lay.extend({},m)),c.setFullYear(m.year,m.month,1),l=c.getDay(),i=n.getEndDate(m.month||12,m.year),r=n.getEndDate(m.month+1,m.year),lay.each(p,function(e,t){var a=[m.year,m.month],n=0;t=lay(t),t.removeAttr("class"),e=l&&e=a.firstDate.year&&(i.month=n.max.month,i.date=n.max.date),a.limit(lay(l),i,t),C++}),lay(c[v?0:1]).attr("lay-ym",C-8+"-"+D[1]).html(w+T+" - "+(C-1+T))}else if("month"===e)lay.each(new Array(12),function(e){var l=lay.elem("li",{"lay-ym":e}),r={year:D[0],month:e};e+1==D[1]&&lay(l).addClass(o),l.innerHTML=i.month[e]+(v?"月":""),y.appendChild(l),D[0]=a.firstDate.year&&(r.date=n.max.date),a.limit(lay(l),r,t)}),lay(c[v?0:1]).attr("lay-ym",D[0]+"-"+D[1]).html(D[0]+T);else if("time"===e){var k=function(){lay(y).find("ol").each(function(e,n){lay(n).find("li").each(function(n,l){a.limit(lay(l),[{hours:n},{hours:a[x].hours,minutes:n},{hours:a[x].hours,minutes:a[x].minutes,seconds:n}][e],t,[["hours"],["hours","minutes"],["hours","minutes","seconds"]][e])})}),n.range||a.limit(lay(a.footer).find(f),a[x],0,["hours","minutes","seconds"])};n.range?a[x]||(a[x]={hours:0,minutes:0,seconds:0}):a[x]=l,lay.each([24,60,60],function(e,t){var n=lay.elem("li"),l=["

            "+i.time[e]+"

              "];lay.each(new Array(t),function(t){l.push(""+lay.digit(t,2)+"")}),n.innerHTML=l.join("")+"
            ",y.appendChild(n)}),k()}if(h&&u.removeChild(h),u.appendChild(y),"year"===e||"month"===e)lay(a.elemMain[t]).addClass("laydate-ym-show"),lay(y).find("li").on("click",function(){var i=0|lay(this).attr("lay-ym");if(!lay(this).hasClass(s)){0===t?(l[e]=i,a.limit(lay(a.footer).find(f),null,0)):a.endDate[e]=i;var d="year"===n.type||"month"===n.type;d?(lay(y).find("."+o).removeClass(o),lay(this).addClass(o),"month"===n.type&&"year"===e&&(a.listYM[t][0]=i,r&&(t?l.year=i:a.endDate.year=i),a.list("month",t))):(a.checkDate("limit").calendar(null,t),a.closeList()),a.setBtnStatus(),n.range||(("month"===n.type&&"month"===e||"year"===n.type&&"year"===e)&&a.setValue(a.parse()).remove().done(),a.done(null,"change")),lay(a.footer).find(g).removeClass(s)}});else{var E=lay.elem("span",{"class":p}),b=function(){lay(y).find("ol").each(function(e){var t=this,n=lay(t).find("li");t.scrollTop=30*(a[x][M[e]]-2),t.scrollTop<=0&&n.each(function(e,a){if(!lay(this).hasClass(s))return t.scrollTop=30*(e-2),!0})})},H=lay(d[2]).find("."+p);b(),E.innerHTML=n.range?[i.startTime,i.endTime][t]:i.timeTips,lay(a.elemMain[t]).addClass("laydate-time-show"),H[0]&&H.remove(),d[2].appendChild(E),lay(y).find("ol").each(function(e){var t=this;lay(t).find("li").on("click",function(){var i=0|this.innerHTML;lay(this).hasClass(s)||(n.range?a[x][M[e]]=i:l[M[e]]=i,lay(t).find("."+o).removeClass(o),lay(this).addClass(o),k(),b(),(a.endDate||"time"===n.type)&&a.done(null,"change"),a.setBtnStatus())})})}return a},v.prototype.listYM=[],v.prototype.closeList=function(){var e=this;e.config;lay.each(e.elemCont,function(t,a){lay(this).find("."+m).remove(),lay(e.elemMain[t]).removeClass("laydate-ym-show laydate-time-show")}),lay(e.elem).find("."+p).remove()},v.prototype.setBtnStatus=function(e,t,a){var n,l=this,i=l.config,r=l.lang(),o=lay(l.footer).find(f);i.range&&"time"!==i.type&&(t=t||i.dateTime,a=a||l.endDate,n=l.newDate(t).getTime()>l.newDate(a).getTime(),l.limit(null,t)||l.limit(null,a)?o.addClass(s):o[n?"addClass":"removeClass"](s),e&&n&&l.hint("string"==typeof e?r.timeout.replace(/日期/g,e):r.timeout))},v.prototype.parse=function(e,t){var a=this,n=a.config,l=t||(e?lay.extend({},a.endDate,a.endTime):n.range?lay.extend({},n.dateTime,a.startTime):n.dateTime),i=a.format.concat();return lay.each(i,function(e,t){/yyyy|y/.test(t)?i[e]=lay.digit(l.year,t.length):/MM|M/.test(t)?i[e]=lay.digit(l.month+1,t.length):/dd|d/.test(t)?i[e]=lay.digit(l.date,t.length):/HH|H/.test(t)?i[e]=lay.digit(l.hours,t.length):/mm|m/.test(t)?i[e]=lay.digit(l.minutes,t.length):/ss|s/.test(t)&&(i[e]=lay.digit(l.seconds,t.length))}),n.range&&!e?i.join("")+" "+n.range+" "+a.parse(1):i.join("")},v.prototype.newDate=function(e){return e=e||{},new Date(e.year||1,e.month||0,e.date||1,e.hours||0,e.minutes||0,e.seconds||0)},v.prototype.setValue=function(e){var t=this,a=t.config,n=t.bindElem||a.elem[0],l=t.isInput(n)?"val":"html";return"static"===a.position||lay(n)[l](e||""),this},v.prototype.stampRange=function(e,t){var a,n,l=this,i=l.config;i.range&&(a=l.newDate(i.dateTime).getTime(),n=l.newDate(l.endDate).getTime(),lay.each(t,function(t,i){var r=lay(i).attr("lay-ymd").split("-"),o=l.newDate({year:r[0],month:r[1]-1,date:r[2]}).getTime();0==e?o>a&&lay(i).addClass(c):o0&&t-1 in e)}function r(e,t,n){if(pe.isFunction(t))return pe.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return pe.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(Ce.test(t))return pe.filter(t,e,n);t=pe.filter(t,e)}return pe.grep(e,function(e){return pe.inArray(e,t)>-1!==n})}function i(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function o(e){var t={};return pe.each(e.match(De)||[],function(e,n){t[n]=!0}),t}function a(){re.addEventListener?(re.removeEventListener("DOMContentLoaded",s),e.removeEventListener("load",s)):(re.detachEvent("onreadystatechange",s),e.detachEvent("onload",s))}function s(){(re.addEventListener||"load"===e.event.type||"complete"===re.readyState)&&(a(),pe.ready())}function u(e,t,n){if(void 0===n&&1===e.nodeType){var r="data-"+t.replace(_e,"-$1").toLowerCase();if(n=e.getAttribute(r),"string"==typeof n){try{n="true"===n||"false"!==n&&("null"===n?null:+n+""===n?+n:qe.test(n)?pe.parseJSON(n):n)}catch(i){}pe.data(e,t,n)}else n=void 0}return n}function l(e){var t;for(t in e)if(("data"!==t||!pe.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function c(e,t,n,r){if(He(e)){var i,o,a=pe.expando,s=e.nodeType,u=s?pe.cache:e,l=s?e[a]:e[a]&&a;if(l&&u[l]&&(r||u[l].data)||void 0!==n||"string"!=typeof t)return l||(l=s?e[a]=ne.pop()||pe.guid++:a),u[l]||(u[l]=s?{}:{toJSON:pe.noop}),"object"!=typeof t&&"function"!=typeof t||(r?u[l]=pe.extend(u[l],t):u[l].data=pe.extend(u[l].data,t)),o=u[l],r||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[pe.camelCase(t)]=n),"string"==typeof t?(i=o[t],null==i&&(i=o[pe.camelCase(t)])):i=o,i}}function f(e,t,n){if(He(e)){var r,i,o=e.nodeType,a=o?pe.cache:e,s=o?e[pe.expando]:pe.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){pe.isArray(t)?t=t.concat(pe.map(t,pe.camelCase)):t in r?t=[t]:(t=pe.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;for(;i--;)delete r[t[i]];if(n?!l(r):!pe.isEmptyObject(r))return}(n||(delete a[s].data,l(a[s])))&&(o?pe.cleanData([e],!0):fe.deleteExpando||a!=a.window?delete a[s]:a[s]=void 0)}}}function d(e,t,n,r){var i,o=1,a=20,s=r?function(){return r.cur()}:function(){return pe.css(e,t,"")},u=s(),l=n&&n[3]||(pe.cssNumber[t]?"":"px"),c=(pe.cssNumber[t]||"px"!==l&&+u)&&Me.exec(pe.css(e,t));if(c&&c[3]!==l){l=l||c[3],n=n||[],c=+u||1;do o=o||".5",c/=o,pe.style(e,t,c+l);while(o!==(o=s()/u)&&1!==o&&--a)}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}function p(e){var t=ze.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function h(e,t){var n,r,i=0,o="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):void 0;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||pe.nodeName(r,t)?o.push(r):pe.merge(o,h(r,t));return void 0===t||t&&pe.nodeName(e,t)?pe.merge([e],o):o}function g(e,t){for(var n,r=0;null!=(n=e[r]);r++)pe._data(n,"globalEval",!t||pe._data(t[r],"globalEval"))}function m(e){Be.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t,n,r,i){for(var o,a,s,u,l,c,f,d=e.length,y=p(t),v=[],x=0;x"!==f[1]||Ve.test(a)?0:u:u.firstChild,o=a&&a.childNodes.length;o--;)pe.nodeName(c=a.childNodes[o],"tbody")&&!c.childNodes.length&&a.removeChild(c);for(pe.merge(v,u.childNodes),u.textContent="";u.firstChild;)u.removeChild(u.firstChild);u=y.lastChild}else v.push(t.createTextNode(a));for(u&&y.removeChild(u),fe.appendChecked||pe.grep(h(v,"input"),m),x=0;a=v[x++];)if(r&&pe.inArray(a,r)>-1)i&&i.push(a);else if(s=pe.contains(a.ownerDocument,a),u=h(y.appendChild(a),"script"),s&&g(u),n)for(o=0;a=u[o++];)Ie.test(a.type||"")&&n.push(a);return u=null,y}function v(){return!0}function x(){return!1}function b(){try{return re.activeElement}catch(e){}}function w(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)w(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),i===!1)i=x;else if(!i)return e;return 1===o&&(a=i,i=function(e){return pe().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=pe.guid++)),e.each(function(){pe.event.add(this,t,i,r,n)})}function T(e,t){return pe.nodeName(e,"table")&&pe.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function C(e){return e.type=(null!==pe.find.attr(e,"type"))+"/"+e.type,e}function E(e){var t=it.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function N(e,t){if(1===t.nodeType&&pe.hasData(e)){var n,r,i,o=pe._data(e),a=pe._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;r1&&"string"==typeof p&&!fe.checkClone&&rt.test(p))return e.each(function(i){var o=e.eq(i);g&&(t[0]=p.call(this,i,o.html())),S(o,t,n,r)});if(f&&(l=y(t,e[0].ownerDocument,!1,e,r),i=l.firstChild,1===l.childNodes.length&&(l=i),i||r)){for(s=pe.map(h(l,"script"),C),a=s.length;c")).appendTo(t.documentElement),t=(ut[0].contentWindow||ut[0].contentDocument).document,t.write(),t.close(),n=D(e,t),ut.detach()),lt[e]=n),n}function L(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function H(e){if(e in Et)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=Ct.length;n--;)if(e=Ct[n]+t,e in Et)return e}function q(e,t){for(var n,r,i,o=[],a=0,s=e.length;a=0&&n=0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},isPlainObject:function(e){var t;if(!e||"object"!==pe.type(e)||e.nodeType||pe.isWindow(e))return!1;try{if(e.constructor&&!ce.call(e,"constructor")&&!ce.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}if(!fe.ownFirst)for(t in e)return ce.call(e,t);for(t in e);return void 0===t||ce.call(e,t)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?ue[le.call(e)]||"object":typeof e},globalEval:function(t){t&&pe.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(ge,"ms-").replace(me,ye)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var r,i=0;if(n(e))for(r=e.length;iT.cacheLength&&delete e[t.shift()],e[n+" "]=r}var t=[];return e}function r(e){return e[P]=!0,e}function i(e){var t=H.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split("|"),r=n.length;r--;)T.attrHandle[n[r]]=t}function a(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||V)-(~e.sourceIndex||V);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function u(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function l(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function c(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function f(){}function d(e){for(var t=0,n=e.length,r="";t1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,n,r){for(var i=0,o=n.length;i-1&&(r[l]=!(a[l]=f))}}else x=m(x===a?x.splice(h,x.length):x),o?o(null,a,x,u):Q.apply(a,x)})}function v(e){for(var t,n,r,i=e.length,o=T.relative[e[0].type],a=o||T.relative[" "],s=o?1:0,u=p(function(e){return e===t},a,!0),l=p(function(e){return ee(t,e)>-1},a,!0),c=[function(e,n,r){var i=!o&&(r||n!==A)||((t=n).nodeType?u(e,n,r):l(e,n,r));return t=null,i}];s1&&h(c),s>1&&d(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(se,"$1"),n,s0,o=e.length>0,a=function(r,a,s,u,l){var c,f,d,p=0,h="0",g=r&&[],y=[],v=A,x=r||o&&T.find.TAG("*",l),b=W+=null==v?1:Math.random()||.1,w=x.length;for(l&&(A=a===H||a||l);h!==w&&null!=(c=x[h]);h++){if(o&&c){for(f=0,a||c.ownerDocument===H||(L(c),s=!_);d=e[f++];)if(d(c,a||H,s)){u.push(c);break}l&&(W=b)}i&&((c=!d&&c)&&p--,r&&g.push(c))}if(p+=h,i&&h!==p){for(f=0;d=n[f++];)d(g,y,a,s);if(r){if(p>0)for(;h--;)g[h]||y[h]||(y[h]=G.call(u));y=m(y)}Q.apply(u,y),l&&!r&&y.length>0&&p+n.length>1&&t.uniqueSort(u)}return l&&(W=b,A=v),g};return i?r(a):a}var b,w,T,C,E,N,k,S,A,D,j,L,H,q,_,F,M,O,R,P="sizzle"+1*new Date,B=e.document,W=0,I=0,$=n(),z=n(),X=n(),U=function(e,t){return e===t&&(j=!0),0},V=1<<31,Y={}.hasOwnProperty,J=[],G=J.pop,K=J.push,Q=J.push,Z=J.slice,ee=function(e,t){for(var n=0,r=e.length;n+~]|"+ne+")"+ne+"*"),ce=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),fe=new RegExp(oe),de=new RegExp("^"+re+"$"),pe={ID:new RegExp("^#("+re+")"),CLASS:new RegExp("^\\.("+re+")"),TAG:new RegExp("^("+re+"|[*])"),ATTR:new RegExp("^"+ie),PSEUDO:new RegExp("^"+oe),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},he=/^(?:input|select|textarea|button)$/i,ge=/^h\d$/i,me=/^[^{]+\{\s*\[native \w/,ye=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ve=/[+~]/,xe=/'|\\/g,be=new RegExp("\\\\([\\da-f]{1,6}"+ne+"?|("+ne+")|.)","ig"),we=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},Te=function(){L()};try{Q.apply(J=Z.call(B.childNodes),B.childNodes),J[B.childNodes.length].nodeType}catch(Ce){Q={apply:J.length?function(e,t){K.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}w=t.support={},E=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},L=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:B;return r!==H&&9===r.nodeType&&r.documentElement?(H=r,q=H.documentElement,_=!E(H),(n=H.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",Te,!1):n.attachEvent&&n.attachEvent("onunload",Te)),w.attributes=i(function(e){return e.className="i",!e.getAttribute("className")}),w.getElementsByTagName=i(function(e){return e.appendChild(H.createComment("")),!e.getElementsByTagName("*").length}),w.getElementsByClassName=me.test(H.getElementsByClassName),w.getById=i(function(e){return q.appendChild(e).id=P,!H.getElementsByName||!H.getElementsByName(P).length}),w.getById?(T.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&_){var n=t.getElementById(e);return n?[n]:[]}},T.filter.ID=function(e){var t=e.replace(be,we);return function(e){return e.getAttribute("id")===t}}):(delete T.find.ID,T.filter.ID=function(e){var t=e.replace(be,we);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}}),T.find.TAG=w.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):w.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},T.find.CLASS=w.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&_)return t.getElementsByClassName(e)},M=[],F=[],(w.qsa=me.test(H.querySelectorAll))&&(i(function(e){q.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&F.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||F.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+P+"-]").length||F.push("~="),e.querySelectorAll(":checked").length||F.push(":checked"),e.querySelectorAll("a#"+P+"+*").length||F.push(".#.+[+~]")}),i(function(e){var t=H.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&F.push("name"+ne+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||F.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),F.push(",.*:")})),(w.matchesSelector=me.test(O=q.matches||q.webkitMatchesSelector||q.mozMatchesSelector||q.oMatchesSelector||q.msMatchesSelector))&&i(function(e){w.disconnectedMatch=O.call(e,"div"),O.call(e,"[s!='']:x"),M.push("!=",oe)}),F=F.length&&new RegExp(F.join("|")),M=M.length&&new RegExp(M.join("|")),t=me.test(q.compareDocumentPosition),R=t||me.test(q.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},U=t?function(e,t){if(e===t)return j=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!w.sortDetached&&t.compareDocumentPosition(e)===n?e===H||e.ownerDocument===B&&R(B,e)?-1:t===H||t.ownerDocument===B&&R(B,t)?1:D?ee(D,e)-ee(D,t):0:4&n?-1:1)}:function(e,t){if(e===t)return j=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],u=[t];if(!i||!o)return e===H?-1:t===H?1:i?-1:o?1:D?ee(D,e)-ee(D,t):0;if(i===o)return a(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;s[r]===u[r];)r++;return r?a(s[r],u[r]):s[r]===B?-1:u[r]===B?1:0},H):H},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==H&&L(e),n=n.replace(ce,"='$1']"),w.matchesSelector&&_&&!X[n+" "]&&(!M||!M.test(n))&&(!F||!F.test(n)))try{var r=O.call(e,n);if(r||w.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return t(n,H,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==H&&L(e),R(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==H&&L(e);var n=T.attrHandle[t.toLowerCase()],r=n&&Y.call(T.attrHandle,t.toLowerCase())?n(e,t,!_):void 0;return void 0!==r?r:w.attributes||!_?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],r=0,i=0;if(j=!w.detectDuplicates,D=!w.sortStable&&e.slice(0),e.sort(U),j){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return D=null,e},C=t.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=C(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=C(t);return n},T=t.selectors={cacheLength:50,createPseudo:r,match:pe,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(be,we),e[3]=(e[3]||e[4]||e[5]||"").replace(be,we),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||t.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return pe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&fe.test(n)&&(t=N(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(be,we).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=$[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&$(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,r){return function(i){var o=t.attr(i,e);return null==o?"!="===n:!n||(o+="","="===n?o===r:"!="===n?o!==r:"^="===n?r&&0===o.indexOf(r):"*="===n?r&&o.indexOf(r)>-1:"$="===n?r&&o.slice(-r.length)===r:"~="===n?(" "+o.replace(ae," ")+" ").indexOf(r)>-1:"|="===n&&(o===r||o.slice(0,r.length+1)===r+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,d,p,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s,x=!1;if(m){if(o){for(;g;){for(d=t;d=d[g];)if(s?d.nodeName.toLowerCase()===y:1===d.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(d=m,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),l=c[e]||[],p=l[0]===W&&l[1],x=p&&l[2], +d=p&&m.childNodes[p];d=++p&&d&&d[g]||(x=p=0)||h.pop();)if(1===d.nodeType&&++x&&d===t){c[e]=[W,p,x];break}}else if(v&&(d=t,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),l=c[e]||[],p=l[0]===W&&l[1],x=p),x===!1)for(;(d=++p&&d&&d[g]||(x=p=0)||h.pop())&&((s?d.nodeName.toLowerCase()!==y:1!==d.nodeType)||!++x||(v&&(f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),c[e]=[W,x]),d!==t)););return x-=i,x===r||x%r===0&&x/r>=0}}},PSEUDO:function(e,n){var i,o=T.pseudos[e]||T.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return o[P]?o(n):o.length>1?(i=[e,e,"",n],T.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,i=o(e,n),a=i.length;a--;)r=ee(e,i[a]),e[r]=!(t[r]=i[a])}):function(e){return o(e,0,i)}):o}},pseudos:{not:r(function(e){var t=[],n=[],i=k(e.replace(se,"$1"));return i[P]?r(function(e,t,n,r){for(var o,a=i(e,null,r,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(be,we),function(t){return(t.textContent||t.innerText||C(t)).indexOf(e)>-1}}),lang:r(function(e){return de.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(be,we).toLowerCase(),function(t){var n;do if(n=_?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===q},focus:function(e){return e===H.activeElement&&(!H.hasFocus||H.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!T.pseudos.empty(e)},header:function(e){return ge.test(e.nodeName)},input:function(e){return he.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r2&&"ID"===(a=o[0]).type&&w.getById&&9===t.nodeType&&_&&T.relative[o[1].type]){if(t=(T.find.ID(a.matches[0].replace(be,we),t)||[])[0],!t)return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=pe.needsContext.test(e)?0:o.length;i--&&(a=o[i],!T.relative[s=a.type]);)if((u=T.find[s])&&(r=u(a.matches[0].replace(be,we),ve.test(o[0].type)&&c(t.parentNode)||t))){if(o.splice(i,1),e=r.length&&d(o),!e)return Q.apply(n,r),n;break}}return(l||k(e,f))(r,t,!_,n,!t||ve.test(e)&&c(t.parentNode)||t),n},w.sortStable=P.split("").sort(U).join("")===P,w.detectDuplicates=!!j,L(),w.sortDetached=i(function(e){return 1&e.compareDocumentPosition(H.createElement("div"))}),i(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||o("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),w.attributes&&i(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||o("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),i(function(e){return null==e.getAttribute("disabled")})||o(te,function(e,t,n){var r;if(!n)return e[t]===!0?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(e);pe.find=ve,pe.expr=ve.selectors,pe.expr[":"]=pe.expr.pseudos,pe.uniqueSort=pe.unique=ve.uniqueSort,pe.text=ve.getText,pe.isXMLDoc=ve.isXML,pe.contains=ve.contains;var xe=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&pe(e).is(n))break;r.push(e)}return r},be=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},we=pe.expr.match.needsContext,Te=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,Ce=/^.[^:#\[\.,]*$/;pe.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?pe.find.matchesSelector(r,e)?[r]:[]:pe.find.matches(e,pe.grep(t,function(e){return 1===e.nodeType}))},pe.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(pe(e).filter(function(){for(t=0;t1?pe.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},filter:function(e){return this.pushStack(r(this,e||[],!1))},not:function(e){return this.pushStack(r(this,e||[],!0))},is:function(e){return!!r(this,"string"==typeof e&&we.test(e)?pe(e):e||[],!1).length}});var Ee,Ne=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,ke=pe.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||Ee,"string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:Ne.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof pe?t[0]:t,pe.merge(this,pe.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:re,!0)),Te.test(r[1])&&pe.isPlainObject(t))for(r in t)pe.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if(i=re.getElementById(r[2]),i&&i.parentNode){if(i.id!==r[2])return Ee.find(e);this.length=1,this[0]=i}return this.context=re,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):pe.isFunction(e)?"undefined"!=typeof n.ready?n.ready(e):e(pe):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),pe.makeArray(e,this))};ke.prototype=pe.fn,Ee=pe(re);var Se=/^(?:parents|prev(?:Until|All))/,Ae={children:!0,contents:!0,next:!0,prev:!0};pe.fn.extend({has:function(e){var t,n=pe(e,this),r=n.length;return this.filter(function(){for(t=0;t-1:1===n.nodeType&&pe.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?pe.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?pe.inArray(this[0],pe(e)):pe.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(pe.uniqueSort(pe.merge(this.get(),pe(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),pe.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return xe(e,"parentNode")},parentsUntil:function(e,t,n){return xe(e,"parentNode",n)},next:function(e){return i(e,"nextSibling")},prev:function(e){return i(e,"previousSibling")},nextAll:function(e){return xe(e,"nextSibling")},prevAll:function(e){return xe(e,"previousSibling")},nextUntil:function(e,t,n){return xe(e,"nextSibling",n)},prevUntil:function(e,t,n){return xe(e,"previousSibling",n)},siblings:function(e){return be((e.parentNode||{}).firstChild,e)},children:function(e){return be(e.firstChild)},contents:function(e){return pe.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:pe.merge([],e.childNodes)}},function(e,t){pe.fn[e]=function(n,r){var i=pe.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=pe.filter(r,i)),this.length>1&&(Ae[e]||(i=pe.uniqueSort(i)),Se.test(e)&&(i=i.reverse())),this.pushStack(i)}});var De=/\S+/g;pe.Callbacks=function(e){e="string"==typeof e?o(e):pe.extend({},e);var t,n,r,i,a=[],s=[],u=-1,l=function(){for(i=e.once,r=t=!0;s.length;u=-1)for(n=s.shift();++u-1;)a.splice(n,1),n<=u&&u--}),this},has:function(e){return e?pe.inArray(e,a)>-1:a.length>0},empty:function(){return a&&(a=[]),this},disable:function(){return i=s=[],a=n="",this},disabled:function(){return!a},lock:function(){return i=!0,n||c.disable(),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=n||[],n=[e,n.slice?n.slice():n],s.push(n),t||l()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},pe.extend({Deferred:function(e){var t=[["resolve","done",pe.Callbacks("once memory"),"resolved"],["reject","fail",pe.Callbacks("once memory"),"rejected"],["notify","progress",pe.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return pe.Deferred(function(n){pe.each(t,function(t,o){var a=pe.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&pe.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[o[0]+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?pe.extend(e,r):r}},i={};return r.pipe=r.then,pe.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=ie.call(arguments),a=o.length,s=1!==a||e&&pe.isFunction(e.promise)?a:0,u=1===s?e:pe.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?ie.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=new Array(a),n=new Array(a),r=new Array(a);i0||(je.resolveWith(re,[pe]),pe.fn.triggerHandler&&(pe(re).triggerHandler("ready"),pe(re).off("ready"))))}}),pe.ready.promise=function(t){if(!je)if(je=pe.Deferred(),"complete"===re.readyState||"loading"!==re.readyState&&!re.documentElement.doScroll)e.setTimeout(pe.ready);else if(re.addEventListener)re.addEventListener("DOMContentLoaded",s),e.addEventListener("load",s);else{re.attachEvent("onreadystatechange",s),e.attachEvent("onload",s);var n=!1;try{n=null==e.frameElement&&re.documentElement}catch(r){}n&&n.doScroll&&!function i(){if(!pe.isReady){try{n.doScroll("left")}catch(t){return e.setTimeout(i,50)}a(),pe.ready()}}()}return je.promise(t)},pe.ready.promise();var Le;for(Le in pe(fe))break;fe.ownFirst="0"===Le,fe.inlineBlockNeedsLayout=!1,pe(function(){var e,t,n,r;n=re.getElementsByTagName("body")[0],n&&n.style&&(t=re.createElement("div"),r=re.createElement("div"),r.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",n.appendChild(r).appendChild(t),"undefined"!=typeof t.style.zoom&&(t.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",fe.inlineBlockNeedsLayout=e=3===t.offsetWidth,e&&(n.style.zoom=1)),n.removeChild(r))}),function(){var e=re.createElement("div");fe.deleteExpando=!0;try{delete e.test}catch(t){fe.deleteExpando=!1}e=null}();var He=function(e){var t=pe.noData[(e.nodeName+" ").toLowerCase()],n=+e.nodeType||1;return(1===n||9===n)&&(!t||t!==!0&&e.getAttribute("classid")===t)},qe=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,_e=/([A-Z])/g;pe.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?pe.cache[e[pe.expando]]:e[pe.expando],!!e&&!l(e)},data:function(e,t,n){return c(e,t,n)},removeData:function(e,t){return f(e,t)},_data:function(e,t,n){return c(e,t,n,!0)},_removeData:function(e,t){return f(e,t,!0)}}),pe.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=pe.data(o),1===o.nodeType&&!pe._data(o,"parsedAttrs"))){for(n=a.length;n--;)a[n]&&(r=a[n].name,0===r.indexOf("data-")&&(r=pe.camelCase(r.slice(5)),u(o,r,i[r])));pe._data(o,"parsedAttrs",!0)}return i}return"object"==typeof e?this.each(function(){pe.data(this,e)}):arguments.length>1?this.each(function(){pe.data(this,e,t)}):o?u(o,e,pe.data(o,e)):void 0},removeData:function(e){return this.each(function(){pe.removeData(this,e)})}}),pe.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=pe._data(e,t),n&&(!r||pe.isArray(n)?r=pe._data(e,t,pe.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=pe.queue(e,t),r=n.length,i=n.shift(),o=pe._queueHooks(e,t),a=function(){pe.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return pe._data(e,n)||pe._data(e,n,{empty:pe.Callbacks("once memory").add(function(){pe._removeData(e,t+"queue"),pe._removeData(e,n)})})}}),pe.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length
            a",fe.leadingWhitespace=3===e.firstChild.nodeType,fe.tbody=!e.getElementsByTagName("tbody").length,fe.htmlSerialize=!!e.getElementsByTagName("link").length,fe.html5Clone="<:nav>"!==re.createElement("nav").cloneNode(!0).outerHTML,n.type="checkbox",n.checked=!0,t.appendChild(n),fe.appendChecked=n.checked,e.innerHTML="",fe.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue,t.appendChild(e),n=re.createElement("input"),n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),e.appendChild(n),fe.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,fe.noCloneEvent=!!e.addEventListener,e[pe.expando]=1,fe.attributes=!e.getAttribute(pe.expando)}();var Xe={option:[1,""],legend:[1,"
            ","
            "],area:[1,"",""],param:[1,"",""],thead:[1,"","
            "],tr:[2,"","
            "],col:[2,"","
            "],td:[3,"","
            "],_default:fe.htmlSerialize?[0,"",""]:[1,"X
            ","
            "]};Xe.optgroup=Xe.option,Xe.tbody=Xe.tfoot=Xe.colgroup=Xe.caption=Xe.thead,Xe.th=Xe.td;var Ue=/<|&#?\w+;/,Ve=/-1&&(h=p.split("."),p=h.shift(),h.sort()),a=p.indexOf(":")<0&&"on"+p,t=t[pe.expando]?t:new pe.Event(p,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=h.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:pe.makeArray(n,[t]),l=pe.event.special[p]||{},i||!l.trigger||l.trigger.apply(r,n)!==!1)){if(!i&&!l.noBubble&&!pe.isWindow(r)){for(u=l.delegateType||p,Ke.test(u+p)||(s=s.parentNode);s;s=s.parentNode)d.push(s),c=s;c===(r.ownerDocument||re)&&d.push(c.defaultView||c.parentWindow||e)}for(f=0;(s=d[f++])&&!t.isPropagationStopped();)t.type=f>1?u:l.bindType||p,o=(pe._data(s,"events")||{})[t.type]&&pe._data(s,"handle"),o&&o.apply(s,n),o=a&&s[a],o&&o.apply&&He(s)&&(t.result=o.apply(s,n),t.result===!1&&t.preventDefault());if(t.type=p,!i&&!t.isDefaultPrevented()&&(!l._default||l._default.apply(d.pop(),n)===!1)&&He(r)&&a&&r[p]&&!pe.isWindow(r)){c=r[a],c&&(r[a]=null),pe.event.triggered=p;try{r[p]()}catch(g){}pe.event.triggered=void 0,c&&(r[a]=c)}return t.result}},dispatch:function(e){e=pe.event.fix(e);var t,n,r,i,o,a=[],s=ie.call(arguments),u=(pe._data(this,"events")||{})[e.type]||[],l=pe.event.special[e.type]||{};if(s[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){for(a=pe.event.handlers.call(this,e,u),t=0;(i=a[t++])&&!e.isPropagationStopped();)for(e.currentTarget=i.elem,n=0;(o=i.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(o.namespace)||(e.handleObj=o,e.data=o.data,r=((pe.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s),void 0!==r&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,a=[],s=t.delegateCount,u=e.target;if(s&&u.nodeType&&("click"!==e.type||isNaN(e.button)||e.button<1))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(r=[],n=0;n-1:pe.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&a.push({elem:u,handlers:r})}return s]","i"),tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,nt=/\s*$/g,at=p(re),st=at.appendChild(re.createElement("div"));pe.extend({htmlPrefilter:function(e){return e.replace(tt,"<$1>")},clone:function(e,t,n){var r,i,o,a,s,u=pe.contains(e.ownerDocument,e);if(fe.html5Clone||pe.isXMLDoc(e)||!et.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(st.innerHTML=e.outerHTML,st.removeChild(o=st.firstChild)),!(fe.noCloneEvent&&fe.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||pe.isXMLDoc(e)))for(r=h(o),s=h(e),a=0;null!=(i=s[a]);++a)r[a]&&k(i,r[a]);if(t)if(n)for(s=s||h(e),r=r||h(o),a=0;null!=(i=s[a]);a++)N(i,r[a]);else N(e,o);return r=h(o,"script"),r.length>0&&g(r,!u&&h(e,"script")),r=s=i=null,o},cleanData:function(e,t){for(var n,r,i,o,a=0,s=pe.expando,u=pe.cache,l=fe.attributes,c=pe.event.special;null!=(n=e[a]);a++)if((t||He(n))&&(i=n[s],o=i&&u[i])){if(o.events)for(r in o.events)c[r]?pe.event.remove(n,r):pe.removeEvent(n,r,o.handle);u[i]&&(delete u[i],l||"undefined"==typeof n.removeAttribute?n[s]=void 0:n.removeAttribute(s),ne.push(i))}}}),pe.fn.extend({domManip:S,detach:function(e){return A(this,e,!0)},remove:function(e){return A(this,e)},text:function(e){return Pe(this,function(e){return void 0===e?pe.text(this):this.empty().append((this[0]&&this[0].ownerDocument||re).createTextNode(e))},null,e,arguments.length)},append:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.appendChild(e)}})},prepend:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&pe.cleanData(h(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&pe.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return pe.clone(this,e,t)})},html:function(e){return Pe(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e)return 1===t.nodeType?t.innerHTML.replace(Ze,""):void 0;if("string"==typeof e&&!nt.test(e)&&(fe.htmlSerialize||!et.test(e))&&(fe.leadingWhitespace||!$e.test(e))&&!Xe[(We.exec(e)||["",""])[1].toLowerCase()]){e=pe.htmlPrefilter(e);try{for(;nt",l.childNodes[0].style.borderCollapse="separate",t=l.getElementsByTagName("td"),t[0].style.cssText="margin:0;border:0;padding:0;display:none",o=0===t[0].offsetHeight,o&&(t[0].style.display="",t[1].style.display="none",o=0===t[0].offsetHeight)),f.removeChild(u)}var n,r,i,o,a,s,u=re.createElement("div"),l=re.createElement("div");l.style&&(l.style.cssText="float:left;opacity:.5",fe.opacity="0.5"===l.style.opacity,fe.cssFloat=!!l.style.cssFloat,l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",fe.clearCloneStyle="content-box"===l.style.backgroundClip,u=re.createElement("div"),u.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",l.innerHTML="",u.appendChild(l),fe.boxSizing=""===l.style.boxSizing||""===l.style.MozBoxSizing||""===l.style.WebkitBoxSizing,pe.extend(fe,{reliableHiddenOffsets:function(){return null==n&&t(),o},boxSizingReliable:function(){return null==n&&t(),i},pixelMarginRight:function(){return null==n&&t(),r},pixelPosition:function(){return null==n&&t(),n},reliableMarginRight:function(){return null==n&&t(),a},reliableMarginLeft:function(){return null==n&&t(),s}}))}();var ht,gt,mt=/^(top|right|bottom|left)$/;e.getComputedStyle?(ht=function(t){var n=t.ownerDocument.defaultView;return n&&n.opener||(n=e),n.getComputedStyle(t)},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n.getPropertyValue(t)||n[t]:void 0,""!==a&&void 0!==a||pe.contains(e.ownerDocument,e)||(a=pe.style(e,t)),n&&!fe.pixelMarginRight()&&ft.test(a)&&ct.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o),void 0===a?a:a+""}):pt.currentStyle&&(ht=function(e){return e.currentStyle},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n[t]:void 0,null==a&&s&&s[t]&&(a=s[t]),ft.test(a)&&!mt.test(t)&&(r=s.left,i=e.runtimeStyle,o=i&&i.left,o&&(i.left=e.currentStyle.left),s.left="fontSize"===t?"1em":a,a=s.pixelLeft+"px",s.left=r,o&&(i.left=o)),void 0===a?a:a+""||"auto"});var yt=/alpha\([^)]*\)/i,vt=/opacity\s*=\s*([^)]*)/i,xt=/^(none|table(?!-c[ea]).+)/,bt=new RegExp("^("+Fe+")(.*)$","i"),wt={position:"absolute",visibility:"hidden",display:"block"},Tt={letterSpacing:"0",fontWeight:"400"},Ct=["Webkit","O","Moz","ms"],Et=re.createElement("div").style;pe.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=gt(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":fe.cssFloat?"cssFloat":"styleFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=pe.camelCase(t),u=e.style;if(t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:u[t];if(o=typeof n,"string"===o&&(i=Me.exec(n))&&i[1]&&(n=d(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(pe.cssNumber[s]?"":"px")),fe.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),!(a&&"set"in a&&void 0===(n=a.set(e,n,r)))))try{u[t]=n}catch(l){}}},css:function(e,t,n,r){var i,o,a,s=pe.camelCase(t);return t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],a&&"get"in a&&(o=a.get(e,!0,n)),void 0===o&&(o=gt(e,t,r)),"normal"===o&&t in Tt&&(o=Tt[t]),""===n||n?(i=parseFloat(o),n===!0||isFinite(i)?i||0:o):o}}),pe.each(["height","width"],function(e,t){pe.cssHooks[t]={get:function(e,n,r){if(n)return xt.test(pe.css(e,"display"))&&0===e.offsetWidth?dt(e,wt,function(){return M(e,t,r)}):M(e,t,r)},set:function(e,n,r){var i=r&&ht(e);return _(e,n,r?F(e,t,r,fe.boxSizing&&"border-box"===pe.css(e,"boxSizing",!1,i),i):0)}}}),fe.opacity||(pe.cssHooks.opacity={get:function(e,t){return vt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=pe.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===pe.trim(o.replace(yt,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=yt.test(o)?o.replace(yt,i):o+" "+i)}}),pe.cssHooks.marginRight=L(fe.reliableMarginRight,function(e,t){if(t)return dt(e,{display:"inline-block"},gt,[e,"marginRight"])}),pe.cssHooks.marginLeft=L(fe.reliableMarginLeft,function(e,t){if(t)return(parseFloat(gt(e,"marginLeft"))||(pe.contains(e.ownerDocument,e)?e.getBoundingClientRect().left-dt(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}):0))+"px"}),pe.each({margin:"",padding:"",border:"Width"},function(e,t){pe.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+Oe[r]+t]=o[r]||o[r-2]||o[0];return i}},ct.test(e)||(pe.cssHooks[e+t].set=_)}),pe.fn.extend({css:function(e,t){return Pe(this,function(e,t,n){var r,i,o={},a=0;if(pe.isArray(t)){for(r=ht(e),i=t.length;a1)},show:function(){return q(this,!0)},hide:function(){return q(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Re(this)?pe(this).show():pe(this).hide()})}}),pe.Tween=O,O.prototype={constructor:O,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||pe.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(pe.cssNumber[n]?"":"px")},cur:function(){var e=O.propHooks[this.prop];return e&&e.get?e.get(this):O.propHooks._default.get(this)},run:function(e){var t,n=O.propHooks[this.prop];return this.options.duration?this.pos=t=pe.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):O.propHooks._default.set(this),this}},O.prototype.init.prototype=O.prototype,O.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=pe.css(e.elem,e.prop,""),t&&"auto"!==t?t:0)},set:function(e){pe.fx.step[e.prop]?pe.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[pe.cssProps[e.prop]]&&!pe.cssHooks[e.prop]?e.elem[e.prop]=e.now:pe.style(e.elem,e.prop,e.now+e.unit)}}},O.propHooks.scrollTop=O.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},pe.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},pe.fx=O.prototype.init,pe.fx.step={};var Nt,kt,St=/^(?:toggle|show|hide)$/,At=/queueHooks$/;pe.Animation=pe.extend($,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return d(n.elem,e,Me.exec(t),n),n}]},tweener:function(e,t){pe.isFunction(e)?(t=e,e=["*"]):e=e.match(De);for(var n,r=0,i=e.length;r
            a",e=n.getElementsByTagName("a")[0],t.setAttribute("type","checkbox"),n.appendChild(t),e=n.getElementsByTagName("a")[0],e.style.cssText="top:1px",fe.getSetAttribute="t"!==n.className,fe.style=/top/.test(e.getAttribute("style")),fe.hrefNormalized="/a"===e.getAttribute("href"),fe.checkOn=!!t.value,fe.optSelected=i.selected,fe.enctype=!!re.createElement("form").enctype,r.disabled=!0,fe.optDisabled=!i.disabled,t=re.createElement("input"),t.setAttribute("value",""),fe.input=""===t.getAttribute("value"),t.value="t",t.setAttribute("type","radio"),fe.radioValue="t"===t.value}();var Dt=/\r/g,jt=/[\x20\t\r\n\f]+/g;pe.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=pe.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,pe(this).val()):e,null==i?i="":"number"==typeof i?i+="":pe.isArray(i)&&(i=pe.map(i,function(e){return null==e?"":e+""})),t=pe.valHooks[this.type]||pe.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return t=pe.valHooks[i.type]||pe.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:(n=i.value,"string"==typeof n?n.replace(Dt,""):null==n?"":n)}}}),pe.extend({valHooks:{option:{get:function(e){var t=pe.find.attr(e,"value");return null!=t?t:pe.trim(pe.text(e)).replace(jt," ")}},select:{get:function(e){for(var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||i<0,a=o?null:[],s=o?i+1:r.length,u=i<0?s:o?i:0;u-1)try{r.selected=n=!0}catch(s){r.scrollHeight}else r.selected=!1;return n||(e.selectedIndex=-1),i}}}}),pe.each(["radio","checkbox"],function(){pe.valHooks[this]={set:function(e,t){if(pe.isArray(t))return e.checked=pe.inArray(pe(e).val(),t)>-1}},fe.checkOn||(pe.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Lt,Ht,qt=pe.expr.attrHandle,_t=/^(?:checked|selected)$/i,Ft=fe.getSetAttribute,Mt=fe.input;pe.fn.extend({attr:function(e,t){return Pe(this,pe.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){pe.removeAttr(this,e)})}}),pe.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?pe.prop(e,t,n):(1===o&&pe.isXMLDoc(e)||(t=t.toLowerCase(),i=pe.attrHooks[t]||(pe.expr.match.bool.test(t)?Ht:Lt)),void 0!==n?null===n?void pe.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:(r=pe.find.attr(e,t),null==r?void 0:r))},attrHooks:{type:{set:function(e,t){if(!fe.radioValue&&"radio"===t&&pe.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(De);if(o&&1===e.nodeType)for(;n=o[i++];)r=pe.propFix[n]||n,pe.expr.match.bool.test(n)?Mt&&Ft||!_t.test(n)?e[r]=!1:e[pe.camelCase("default-"+n)]=e[r]=!1:pe.attr(e,n,""),e.removeAttribute(Ft?n:r)}}),Ht={set:function(e,t,n){return t===!1?pe.removeAttr(e,n):Mt&&Ft||!_t.test(n)?e.setAttribute(!Ft&&pe.propFix[n]||n,n):e[pe.camelCase("default-"+n)]=e[n]=!0,n}},pe.each(pe.expr.match.bool.source.match(/\w+/g),function(e,t){var n=qt[t]||pe.find.attr;Mt&&Ft||!_t.test(t)?qt[t]=function(e,t,r){var i,o;return r||(o=qt[t],qt[t]=i,i=null!=n(e,t,r)?t.toLowerCase():null,qt[t]=o),i}:qt[t]=function(e,t,n){if(!n)return e[pe.camelCase("default-"+t)]?t.toLowerCase():null}}),Mt&&Ft||(pe.attrHooks.value={set:function(e,t,n){return pe.nodeName(e,"input")?void(e.defaultValue=t):Lt&&Lt.set(e,t,n)}}),Ft||(Lt={set:function(e,t,n){var r=e.getAttributeNode(n);if(r||e.setAttributeNode(r=e.ownerDocument.createAttribute(n)),r.value=t+="","value"===n||t===e.getAttribute(n))return t}},qt.id=qt.name=qt.coords=function(e,t,n){var r;if(!n)return(r=e.getAttributeNode(t))&&""!==r.value?r.value:null},pe.valHooks.button={get:function(e,t){var n=e.getAttributeNode(t);if(n&&n.specified)return n.value},set:Lt.set},pe.attrHooks.contenteditable={set:function(e,t,n){Lt.set(e,""!==t&&t,n)}},pe.each(["width","height"],function(e,t){pe.attrHooks[t]={set:function(e,n){if(""===n)return e.setAttribute(t,"auto"),n}}})),fe.style||(pe.attrHooks.style={get:function(e){return e.style.cssText||void 0},set:function(e,t){return e.style.cssText=t+""}});var Ot=/^(?:input|select|textarea|button|object)$/i,Rt=/^(?:a|area)$/i;pe.fn.extend({prop:function(e,t){return Pe(this,pe.prop,e,t,arguments.length>1)},removeProp:function(e){return e=pe.propFix[e]||e,this.each(function(){try{this[e]=void 0,delete this[e]}catch(t){}})}}),pe.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&pe.isXMLDoc(e)||(t=pe.propFix[t]||t,i=pe.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=pe.find.attr(e,"tabindex");return t?parseInt(t,10):Ot.test(e.nodeName)||Rt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),fe.hrefNormalized||pe.each(["href","src"],function(e,t){pe.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),fe.optSelected||(pe.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),pe.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){pe.propFix[this.toLowerCase()]=this}),fe.enctype||(pe.propFix.enctype="encoding");var Pt=/[\t\r\n\f]/g;pe.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).addClass(e.call(this,t,z(this)))});if("string"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(" "+i+" ").replace(Pt," ")){for(a=0;o=t[a++];)r.indexOf(" "+o+" ")<0&&(r+=o+" ");s=pe.trim(r),i!==s&&pe.attr(n,"class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).removeClass(e.call(this,t,z(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(" "+i+" ").replace(Pt," ")){for(a=0;o=t[a++];)for(;r.indexOf(" "+o+" ")>-1;)r=r.replace(" "+o+" "," ");s=pe.trim(r),i!==s&&pe.attr(n,"class",s)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):pe.isFunction(e)?this.each(function(n){pe(this).toggleClass(e.call(this,n,z(this),t),t)}):this.each(function(){var t,r,i,o;if("string"===n)for(r=0,i=pe(this),o=e.match(De)||[];t=o[r++];)i.hasClass(t)?i.removeClass(t):i.addClass(t);else void 0!==e&&"boolean"!==n||(t=z(this),t&&pe._data(this,"__className__",t),pe.attr(this,"class",t||e===!1?"":pe._data(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+z(n)+" ").replace(Pt," ").indexOf(t)>-1)return!0;return!1}}),pe.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){pe.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),pe.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}});var Bt=e.location,Wt=pe.now(),It=/\?/,$t=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;pe.parseJSON=function(t){if(e.JSON&&e.JSON.parse)return e.JSON.parse(t+"");var n,r=null,i=pe.trim(t+"");return i&&!pe.trim(i.replace($t,function(e,t,i,o){return n&&t&&(r=0),0===r?e:(n=i||t,r+=!o-!i,"")}))?Function("return "+i)():pe.error("Invalid JSON: "+t)},pe.parseXML=function(t){var n,r;if(!t||"string"!=typeof t)return null;try{e.DOMParser?(r=new e.DOMParser,n=r.parseFromString(t,"text/xml")):(n=new e.ActiveXObject("Microsoft.XMLDOM"),n.async="false",n.loadXML(t))}catch(i){n=void 0}return n&&n.documentElement&&!n.getElementsByTagName("parsererror").length||pe.error("Invalid XML: "+t),n};var zt=/#.*$/,Xt=/([?&])_=[^&]*/,Ut=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Vt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Yt=/^(?:GET|HEAD)$/,Jt=/^\/\//,Gt=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Kt={},Qt={},Zt="*/".concat("*"),en=Bt.href,tn=Gt.exec(en.toLowerCase())||[];pe.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:en,type:"GET",isLocal:Vt.test(tn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Zt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":pe.parseJSON,"text xml":pe.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?V(V(e,pe.ajaxSettings),t):V(pe.ajaxSettings,e)},ajaxPrefilter:X(Kt),ajaxTransport:X(Qt),ajax:function(t,n){function r(t,n,r,i){var o,f,v,x,w,C=n;2!==b&&(b=2,u&&e.clearTimeout(u),c=void 0,s=i||"",T.readyState=t>0?4:0,o=t>=200&&t<300||304===t,r&&(x=Y(d,T,r)),x=J(d,x,T,o),o?(d.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(pe.lastModified[a]=w),w=T.getResponseHeader("etag"),w&&(pe.etag[a]=w)),204===t||"HEAD"===d.type?C="nocontent":304===t?C="notmodified":(C=x.state,f=x.data,v=x.error,o=!v)):(v=C,!t&&C||(C="error",t<0&&(t=0))),T.status=t,T.statusText=(n||C)+"",o?g.resolveWith(p,[f,C,T]):g.rejectWith(p,[T,C,v]),T.statusCode(y),y=void 0,l&&h.trigger(o?"ajaxSuccess":"ajaxError",[T,d,o?f:v]),m.fireWith(p,[T,C]),l&&(h.trigger("ajaxComplete",[T,d]),--pe.active||pe.event.trigger("ajaxStop")))}"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,d=pe.ajaxSetup({},n),p=d.context||d,h=d.context&&(p.nodeType||p.jquery)?pe(p):pe.event,g=pe.Deferred(),m=pe.Callbacks("once memory"),y=d.statusCode||{},v={},x={},b=0,w="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!f)for(f={};t=Ut.exec(s);)f[t[1].toLowerCase()]=t[2];t=f[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?s:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=x[n]=x[n]||e,v[e]=t),this},overrideMimeType:function(e){return b||(d.mimeType=e),this},statusCode:function(e){var t;if(e)if(b<2)for(t in e)y[t]=[y[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||w;return c&&c.abort(t),r(0,t),this}};if(g.promise(T).complete=m.add,T.success=T.done,T.error=T.fail,d.url=((t||d.url||en)+"").replace(zt,"").replace(Jt,tn[1]+"//"),d.type=n.method||n.type||d.method||d.type,d.dataTypes=pe.trim(d.dataType||"*").toLowerCase().match(De)||[""],null==d.crossDomain&&(i=Gt.exec(d.url.toLowerCase()),d.crossDomain=!(!i||i[1]===tn[1]&&i[2]===tn[2]&&(i[3]||("http:"===i[1]?"80":"443"))===(tn[3]||("http:"===tn[1]?"80":"443")))),d.data&&d.processData&&"string"!=typeof d.data&&(d.data=pe.param(d.data,d.traditional)),U(Kt,d,n,T),2===b)return T;l=pe.event&&d.global,l&&0===pe.active++&&pe.event.trigger("ajaxStart"),d.type=d.type.toUpperCase(),d.hasContent=!Yt.test(d.type),a=d.url,d.hasContent||(d.data&&(a=d.url+=(It.test(a)?"&":"?")+d.data,delete d.data),d.cache===!1&&(d.url=Xt.test(a)?a.replace(Xt,"$1_="+Wt++):a+(It.test(a)?"&":"?")+"_="+Wt++)),d.ifModified&&(pe.lastModified[a]&&T.setRequestHeader("If-Modified-Since",pe.lastModified[a]),pe.etag[a]&&T.setRequestHeader("If-None-Match",pe.etag[a])),(d.data&&d.hasContent&&d.contentType!==!1||n.contentType)&&T.setRequestHeader("Content-Type",d.contentType),T.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+("*"!==d.dataTypes[0]?", "+Zt+"; q=0.01":""):d.accepts["*"]);for(o in d.headers)T.setRequestHeader(o,d.headers[o]);if(d.beforeSend&&(d.beforeSend.call(p,T,d)===!1||2===b))return T.abort();w="abort";for(o in{success:1,error:1,complete:1})T[o](d[o]);if(c=U(Qt,d,n,T)){if(T.readyState=1,l&&h.trigger("ajaxSend",[T,d]),2===b)return T;d.async&&d.timeout>0&&(u=e.setTimeout(function(){T.abort("timeout")},d.timeout));try{b=1,c.send(v,r)}catch(C){if(!(b<2))throw C;r(-1,C)}}else r(-1,"No Transport");return T},getJSON:function(e,t,n){return pe.get(e,t,n,"json")},getScript:function(e,t){return pe.get(e,void 0,t,"script")}}),pe.each(["get","post"],function(e,t){pe[t]=function(e,n,r,i){return pe.isFunction(n)&&(i=i||r,r=n,n=void 0),pe.ajax(pe.extend({url:e,type:t,dataType:i,data:n,success:r},pe.isPlainObject(e)&&e))}}),pe._evalUrl=function(e){return pe.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},pe.fn.extend({wrapAll:function(e){if(pe.isFunction(e))return this.each(function(t){pe(this).wrapAll(e.call(this,t))});if(this[0]){var t=pe(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstChild&&1===e.firstChild.nodeType;)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return pe.isFunction(e)?this.each(function(t){pe(this).wrapInner(e.call(this,t))}):this.each(function(){var t=pe(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=pe.isFunction(e);return this.each(function(n){pe(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){pe.nodeName(this,"body")||pe(this).replaceWith(this.childNodes)}).end()}}),pe.expr.filters.hidden=function(e){return fe.reliableHiddenOffsets()?e.offsetWidth<=0&&e.offsetHeight<=0&&!e.getClientRects().length:K(e)},pe.expr.filters.visible=function(e){return!pe.expr.filters.hidden(e)};var nn=/%20/g,rn=/\[\]$/,on=/\r?\n/g,an=/^(?:submit|button|image|reset|file)$/i,sn=/^(?:input|select|textarea|keygen)/i;pe.param=function(e,t){var n,r=[],i=function(e,t){t=pe.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(void 0===t&&(t=pe.ajaxSettings&&pe.ajaxSettings.traditional),pe.isArray(e)||e.jquery&&!pe.isPlainObject(e))pe.each(e,function(){i(this.name,this.value)});else for(n in e)Q(n,e[n],t,i);return r.join("&").replace(nn,"+")},pe.fn.extend({serialize:function(){return pe.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=pe.prop(this,"elements");return e?pe.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!pe(this).is(":disabled")&&sn.test(this.nodeName)&&!an.test(e)&&(this.checked||!Be.test(e))}).map(function(e,t){var n=pe(this).val();return null==n?null:pe.isArray(n)?pe.map(n,function(e){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),pe.ajaxSettings.xhr=void 0!==e.ActiveXObject?function(){return this.isLocal?ee():re.documentMode>8?Z():/^(get|post|head|put|delete|options)$/i.test(this.type)&&Z()||ee()}:Z;var un=0,ln={},cn=pe.ajaxSettings.xhr();e.attachEvent&&e.attachEvent("onunload",function(){for(var e in ln)ln[e](void 0,!0)}),fe.cors=!!cn&&"withCredentials"in cn,cn=fe.ajax=!!cn,cn&&pe.ajaxTransport(function(t){if(!t.crossDomain||fe.cors){var n;return{send:function(r,i){var o,a=t.xhr(),s=++un;if(a.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(o in t.xhrFields)a[o]=t.xhrFields[o];t.mimeType&&a.overrideMimeType&&a.overrideMimeType(t.mimeType),t.crossDomain||r["X-Requested-With"]||(r["X-Requested-With"]="XMLHttpRequest");for(o in r)void 0!==r[o]&&a.setRequestHeader(o,r[o]+"");a.send(t.hasContent&&t.data||null),n=function(e,r){var o,u,l;if(n&&(r||4===a.readyState))if(delete ln[s],n=void 0,a.onreadystatechange=pe.noop,r)4!==a.readyState&&a.abort();else{l={},o=a.status,"string"==typeof a.responseText&&(l.text=a.responseText);try{u=a.statusText}catch(c){u=""}o||!t.isLocal||t.crossDomain?1223===o&&(o=204):o=l.text?200:404}l&&i(o,u,l,a.getAllResponseHeaders())},t.async?4===a.readyState?e.setTimeout(n):a.onreadystatechange=ln[s]=n:n()},abort:function(){n&&n(void 0,!0)}}}}),pe.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return pe.globalEval(e),e}}}),pe.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),pe.ajaxTransport("script",function(e){if(e.crossDomain){var t,n=re.head||pe("head")[0]||re.documentElement;return{send:function(r,i){t=re.createElement("script"),t.async=!0,e.scriptCharset&&(t.charset=e.scriptCharset),t.src=e.url,t.onload=t.onreadystatechange=function(e,n){(n||!t.readyState||/loaded|complete/.test(t.readyState))&&(t.onload=t.onreadystatechange=null,t.parentNode&&t.parentNode.removeChild(t),t=null,n||i(200,"success"))},n.insertBefore(t,n.firstChild)},abort:function(){t&&t.onload(void 0,!0)}}}});var fn=[],dn=/(=)\?(?=&|$)|\?\?/;pe.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=fn.pop()||pe.expando+"_"+Wt++;return this[e]=!0,e}}),pe.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,a,s=t.jsonp!==!1&&(dn.test(t.url)?"url":"string"==typeof t.data&&0===(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&dn.test(t.data)&&"data");if(s||"jsonp"===t.dataTypes[0])return i=t.jsonpCallback=pe.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,s?t[s]=t[s].replace(dn,"$1"+i):t.jsonp!==!1&&(t.url+=(It.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return a||pe.error(i+" was not called"),a[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){a=arguments},r.always(function(){void 0===o?pe(e).removeProp(i):e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,fn.push(i)),a&&pe.isFunction(o)&&o(a[0]),a=o=void 0}),"script"}),pe.parseHTML=function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||re;var r=Te.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=y([e],t,i),i&&i.length&&pe(i).remove(),pe.merge([],r.childNodes))};var pn=pe.fn.load;return pe.fn.load=function(e,t,n){if("string"!=typeof e&&pn)return pn.apply(this,arguments);var r,i,o,a=this,s=e.indexOf(" ");return s>-1&&(r=pe.trim(e.slice(s,e.length)),e=e.slice(0,s)),pe.isFunction(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),a.length>0&&pe.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?pe("
            ").append(pe.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},pe.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){pe.fn[t]=function(e){return this.on(t,e)}}),pe.expr.filters.animated=function(e){return pe.grep(pe.timers,function(t){return e===t.elem}).length},pe.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l,c=pe.css(e,"position"),f=pe(e),d={};"static"===c&&(e.style.position="relative"),s=f.offset(),o=pe.css(e,"top"),u=pe.css(e,"left"),l=("absolute"===c||"fixed"===c)&&pe.inArray("auto",[o,u])>-1,l?(r=f.position(),a=r.top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),pe.isFunction(t)&&(t=t.call(e,n,pe.extend({},s))),null!=t.top&&(d.top=t.top-s.top+a),null!=t.left&&(d.left=t.left-s.left+i),"using"in t?t.using.call(e,d):f.css(d)}},pe.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){pe.offset.setOffset(this,e,t)});var t,n,r={top:0,left:0},i=this[0],o=i&&i.ownerDocument;if(o)return t=o.documentElement,pe.contains(t,i)?("undefined"!=typeof i.getBoundingClientRect&&(r=i.getBoundingClientRect()),n=te(o),{top:r.top+(n.pageYOffset||t.scrollTop)-(t.clientTop||0),left:r.left+(n.pageXOffset||t.scrollLeft)-(t.clientLeft||0)}):r},position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===pe.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),pe.nodeName(e[0],"html")||(n=e.offset()),n.top+=pe.css(e[0],"borderTopWidth",!0),n.left+=pe.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-pe.css(r,"marginTop",!0),left:t.left-n.left-pe.css(r,"marginLeft",!0)}}},offsetParent:function(){ +return this.map(function(){for(var e=this.offsetParent;e&&!pe.nodeName(e,"html")&&"static"===pe.css(e,"position");)e=e.offsetParent;return e||pt})}}),pe.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,t){var n=/Y/.test(t);pe.fn[e]=function(r){return Pe(this,function(e,r,i){var o=te(e);return void 0===i?o?t in o?o[t]:o.document.documentElement[r]:e[r]:void(o?o.scrollTo(n?pe(o).scrollLeft():i,n?i:pe(o).scrollTop()):e[r]=i)},e,r,arguments.length,null)}}),pe.each(["top","left"],function(e,t){pe.cssHooks[t]=L(fe.pixelPosition,function(e,n){if(n)return n=gt(e,t),ft.test(n)?pe(e).position()[t]+"px":n})}),pe.each({Height:"height",Width:"width"},function(e,t){pe.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){pe.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),a=n||(r===!0||i===!0?"margin":"border");return Pe(this,function(t,n,r){var i;return pe.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):void 0===r?pe.css(t,n,a):pe.style(t,n,r,a)},t,o?r:void 0,o,null)}})}),pe.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),pe.fn.size=function(){return this.length},pe.fn.andSelf=pe.fn.addBack,layui.define(function(e){layui.$=pe,e("jquery",pe)}),pe});!function(e,t){"use strict";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,i=t.length-1,n=i;n>0;n--)if("interactive"===t[n].readyState){e=t[n].src;break}return e||t[i].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName("head")[0],s=document.createElement("link");"string"==typeof i&&(n=i);var l=(n||t).replace(/\.|\//g,""),f="layuicss-"+l,c=0;s.rel="stylesheet",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),"function"==typeof i&&!function u(){return++c>80?e.console&&console.error("layer.css: Invalid"):void(1989===parseInt(o.getStyle(document.getElementById(f),"width"))?i():setTimeout(u,100))}()}}},r={v:"3.3.0",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||"ActiveXObject"in e)&&((t.match(/msie\s(\d+)/)||[])[1]||"11")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,"string"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss("modules/layer/"+e.extend):o.link("theme/"+e.extend),this):this},ready:function(e){var t="layer",i="",n=(a?"modules/layer/":"theme/")+"default/layer.css?v="+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a="function"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s="function"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s="function"==typeof n,f=o.config.skin,c=(f?f+" "+f+"-msg":"")||"layui-layer-msg",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+" layui-layer-hui",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+" "+(n.skin||"layui-layer-hui")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:260},n))}},s=function(e){var t=this,a=function(){r.ready(function(){t.creat()})};t.index=++r.index,t.config.maxWidth=i(n).width()-30,t.config=i.extend({},t.config,o.config,e),document.body?a():setTimeout(function(){a()},30)};s.pt=s.prototype;var l=["layui-layer",".layui-layer-title",".layui-layer-main",".layui-layer-dialog","layui-layer-iframe","layui-layer-content","layui-layer-btn","layui-layer-close"];l.anim=["layer-anim-00","layer-anim-01","layer-anim-02","layer-anim-03","layer-anim-04","layer-anim-05","layer-anim-06"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:"信息",offset:"auto",area:"auto",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f="object"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'
            '+(f?r.title[0]:r.title)+"
            ":"";return r.zIndex=s,t([r.shade?'
            ':"",'
            '+(e&&2!=r.type?"":u)+'
            '+(0==r.type&&r.icon!==-1?'':"")+(1==r.type&&e?"":r.content||"")+'
            '+function(){var e=c?'':"";return r.closeBtn&&(e+=''),e}()+""+(r.btn?function(){var e="";"string"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t'+r.btn[t]+"";return'
            '+e+"
            "}():"")+(r.resize?'':"")+"
            "],u,i('
            ')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f="object"==typeof s,c=i("body");if(!t.id||!i("#"+t.id)[0]){switch("string"==typeof t.area&&(t.area="auto"===t.area?["",""]:[t.area,""]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn="btn"in t?t.btn:o.btn[0],r.closeAll("dialog");break;case 2:var s=t.content=f?t.content:[t.content||"","auto"];t.content='';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll("loading");break;case 4:f||(t.content=[t.content,"body"]),t.follow=t.content[1],t.content=t.content[0]+'',delete t.title,t.tips="object"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll("tips")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i("body").append(n[1])}():function(){s.parents("."+l[0])[0]||(s.data("display",s.css("display")).show().addClass("layui-layer-wrap").wrap(n[1]),i("#"+l[0]+a).find("."+l[5]).before(r))}()}():c.append(n[1]),i(".layui-layer-move")[0]||c.append(o.moveElem=u),e.layero=i("#"+l[0]+a),t.scrollbar||l.html.css("overflow","hidden").attr("layer-full",a)}).auto(a),i("#layui-layer-shade"+e.index).css({"background-color":t.shade[1]||"#000",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find("iframe").attr("src",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on("resize",function(){e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u="layer-anim "+l.anim[t.anim];e.layero.addClass(u).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data("isOutAnim",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i("#"+l[0]+e);""===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find("."+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css("padding-top"))))};switch(a.type){case 2:u("iframe");break;default:""===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u("."+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u("."+l[5])):u("."+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o="object"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=n.width()-a[0]:"b"===t.offset?e.offsetTop=n.height()-a[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):"rb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i("body"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(".layui-layer-TipsG"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:"auto"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find("."+l[5]).css({"background-color":t.tips[1],"padding-right":t.closeBtn?"30px":""}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(".layui-layer-resize"),c={};return t.move&&l.css("cursor","move"),l.on("mousedown",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css("left")),e.clientY-parseFloat(s.css("top"))],o.moveElem.css("cursor","move").show())}),f.on("mousedown",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css("cursor","se-resize").show()}),a.on("mousemove",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l="fixed"===s.css("position");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;af&&(a=f),ou&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on("mouseup",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find("iframe").on("load",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find("."+l[6]).children("a").on("click",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a["btn"+(e+1)]&&a["btn"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find("."+l[7]).on("click",e),a.shadeClose&&i("#layui-layer-shade"+t.index).on("click",function(){r.close(t.index)}),n.find(".layui-layer-min").on("click",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(".layui-layer-max").on("click",function(){i(this).hasClass("layui-layer-maxmin")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i("select"),function(e,t){var n=i(this);n.parents("."+l[0])[0]||1==n.attr("layer")&&i("."+l[0]).length<1&&n.removeAttr("layer").show(),n=null})},s.pt.IE6=function(e){i("select").each(function(e,t){var n=i(this);n.parents("."+l[0])[0]||"none"===n.css("display")||n.attr({layer:"1"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css("z-index",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on("mousedown",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css("margin-left"))];e.find(".layui-layer-max").addClass("layui-layer-maxmin"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr("layer-full")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty("overflow"):l.html[0].style.removeAttribute("overflow"),l.html.removeAttr("layer-full"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i("."+l[4]).attr("times"),i("#"+l[0]+t).find("iframe").contents().find(e)},r.getFrameIndex=function(e){return i("#"+e).parents("."+l[4]).attr("times")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame("html",e).outerHeight(),n=i("#"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find("."+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find("iframe").css({height:t})}},r.iframeSrc=function(e,t){i("#"+l[0]+e).find("iframe").attr("src",t)},r.style=function(e,t,n){var a=i("#"+l[0]+e),r=a.find(".layui-layer-content"),s=a.attr("type"),f=a.find(l[1]).outerHeight()||0,c=a.find("."+l[6]).outerHeight()||0;a.attr("minLeft");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find("."+l[6]).outerHeight(),s===o.type[2]?a.find("iframe").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom"))}))},r.min=function(e,t){var a=i("#"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr("minLeft")||181*o.minIndex+"px",c=a.css("position");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr("position",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:"fixed",overflow:"hidden"},!0),a.find(".layui-layer-min").hide(),"page"===a.attr("type")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr("minLeft")||o.minIndex++,a.attr("minLeft",f)},r.restore=function(e){var t=i("#"+l[0]+e),n=t.attr("area").split(",");t.attr("type");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr("position"),overflow:"visible"},!0),t.find(".layui-layer-max").removeClass("layui-layer-maxmin"),t.find(".layui-layer-min").show(),"page"===t.attr("type")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i("#"+l[0]+e);o.record(a),l.html.attr("layer-full")||l.html.css("overflow","hidden").attr("layer-full",e),clearTimeout(t),t=setTimeout(function(){var t="fixed"===a.css("position");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(".layui-layer-min").hide()},100)},r.title=function(e,t){var n=i("#"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){r.ready(function(){var t=i("#"+l[0]+e),n=t.attr("type"),a="layer-anim-close";if(t[0]){var s="layui-layer-wrap",f=function(){if(n===o.type[1]&&"object"===t.attr("conType")){t.children(":not(."+l[5]+")").remove();for(var a=t.find("."+s),r=0;r<2;r++)a.unwrap();a.css("display",a.data("display")).removeClass(s)}else{if(n===o.type[2])try{var f=i("#"+l[4]+e)[0];f.contentWindow.document.write(""),f.contentWindow.close(),t.find("."+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML="",t.remove()}"function"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data("isOutAnim")&&t.addClass("layer-anim "+a),i("#layui-layer-moves, #layui-layer-shade"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr("minLeft")&&(o.minIndex--,o.minLeft.push(t.attr("minLeft"))),r.ie&&r.ie<10||!t.data("isOutAnim")?f():setTimeout(function(){f()},200)}})},r.closeAll=function(e){r.ready(function(){i.each(i("."+l[0]),function(){var t=i(this),n=e?t.attr("type")===e:1;n&&r.close(t.attr("times")),n=null})})};var f=r.cache||{},c=function(e){return f.skin?" "+f.skin+" "+f.skin+"-"+e:""};r.prompt=function(e,t){var a="";if(e=e||{},"function"==typeof e&&(t=e),e.area){var o=e.area;a='style="width: '+o[0]+"; height: "+o[1]+';"',delete e.area}var s,l=2==e.formType?'":function(){return''}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:["确定","取消"],content:l,skin:"layui-layer-prompt"+c("prompt"),maxWidth:n.width(),success:function(t){s=t.find(".layui-layer-input"),s.val(e.value||"").focus(),"function"==typeof f&&f(t)},resize:!1,yes:function(i){var n=s.val();""===n?s.focus():n.length>(e.maxlength||500)?r.tips("最多输入"+(e.maxlength||500)+"个字数",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n="layui-this",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:"layui-layer-tab"+c("tab"),resize:!1,title:function(){var e=t.length,i=1,a="";if(e>0)for(a=''+t[0].title+"";i"+t[i].title+"";return a}(),content:'
              '+function(){var e=t.length,i=1,a="";if(e>0)for(a='
            • '+(t[0].content||"no content")+"
            • ";i'+(t[i].content||"no content")+"";return a}()+"
            ",success:function(t){var o=t.find(".layui-layer-title").children(),r=t.find(".layui-layer-tabmain").children();o.on("mousedown",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),"function"==typeof e.change&&e.change(o)}),"function"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||"img";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg("没有图片")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr("layer-index",e),u.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(h(),0===u.length)return;if(n||p.on("click",t.img,function(){var e=i(this),n=e.attr("layer-index");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),s.imgnext()}),i(document).on("keyup",s.keyup)},s.loadi=r.load(1,{shade:!("shade"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:"layui-layer-photos",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]'+(u[d].alt||
            '+(u.length>1?'':"")+'
            '+(u[d].alt||"")+""+s.imgIndex+"/"+u.length+"
            ",success:function(e,i){s.bigimg=e.find(".layui-layer-phimg"),s.imgsee=e.find(".layui-layer-imguide,.layui-layer-imgbar"),s.event(e),t.tab&&t.tab(u[d],e),"function"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off("keyup",s.keyup)}},t))},function(){r.close(s.loadi),r.msg("当前图片地址异常
            是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i("html"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define("jquery",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t("layer",r)})):"function"==typeof define&&define.amd?define(["jquery"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window);layui.define("jquery",function(e){"use strict";var t=layui.$,i={fixbar:function(e){var i,a,n="layui-fixbar",o="layui-fixbar-top",r=t(document),l=t("body");e=t.extend({showHeight:200},e),e.bar1=e.bar1===!0?"":e.bar1,e.bar2=e.bar2===!0?"":e.bar2,e.bgcolor=e.bgcolor?"background-color:"+e.bgcolor:"";var c=[e.bar1,e.bar2,""],g=t(['
              ',e.bar1?'
            • '+c[0]+"
            • ":"",e.bar2?'
            • '+c[1]+"
            • ":"",'
            • '+c[2]+"
            • ","
            "].join("")),u=g.find("."+o),s=function(){var t=r.scrollTop();t>=e.showHeight?i||(u.show(),i=1):i&&(u.hide(),i=0)};t("."+n)[0]||("object"==typeof e.css&&g.css(e.css),l.append(g),s(),g.find("li").on("click",function(){var i=t(this),a=i.attr("lay-type");"top"===a&&t("html,body").animate({scrollTop:0},200),e.click&&e.click.call(this,a)}),r.on("scroll",function(){clearTimeout(a),a=setTimeout(function(){s()},100)}))},countdown:function(e,t,i){var a=this,n="function"==typeof t,o=new Date(e).getTime(),r=new Date(!t||n?(new Date).getTime():t).getTime(),l=o-r,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];n&&(i=t);var g=setTimeout(function(){a.countdown(e,r+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],t,g),l<=0&&clearTimeout(g),g},timeAgo:function(e,t){var i=this,a=[[],[]],n=(new Date).getTime()-new Date(e).getTime();return n>26784e5?(n=new Date(e),a[0][0]=i.digit(n.getFullYear(),4),a[0][1]=i.digit(n.getMonth()+1),a[0][2]=i.digit(n.getDate()),t||(a[1][0]=i.digit(n.getHours()),a[1][1]=i.digit(n.getMinutes()),a[1][2]=i.digit(n.getSeconds())),a[0].join("-")+" "+a[1].join(":")):n>=864e5?(n/1e3/60/60/24|0)+"天前":n>=36e5?(n/1e3/60/60|0)+"小时前":n>=18e4?(n/1e3/60|0)+"分钟前":n<0?"未来":"刚刚"},digit:function(e,t){var i="";e=String(e),t=t||2;for(var a=e.length;a/g,">").replace(/'/g,"'").replace(/"/g,""")},unescape:function(e){return String(e||"").replace(/\&/g,"&").replace(/\</g,"<").replace(/\>/g,">").replace(/\'/,"'").replace(/\"/,'"')},event:function(e,a,n){var o=t("body");return n=n||"click",a=i.event[e]=t.extend(!0,i.event[e],a)||{},i.event.UTIL_EVENT_CALLBACK=i.event.UTIL_EVENT_CALLBACK||{},o.off(n,"*["+e+"]",i.event.UTIL_EVENT_CALLBACK[e]),i.event.UTIL_EVENT_CALLBACK[e]=function(){var i=t(this),n=i.attr(e);"function"==typeof a[n]&&a[n].call(this,i)},o.on(n,"*["+e+"]",i.event.UTIL_EVENT_CALLBACK[e]),a}};e("util",i)});layui.define("jquery",function(t){"use strict";var a=layui.$,i=(layui.hint(),layui.device()),e="element",l="layui-this",n="layui-show",s=function(){this.config={}};s.prototype.set=function(t){var i=this;return a.extend(!0,i.config,t),i},s.prototype.on=function(t,a){return layui.onevent.call(this,e,t,a)},s.prototype.tabAdd=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.children(".layui-tab-bar"),o=l.children(".layui-tab-content"),r='
          • "+(i.title||"unnaming")+"
          • ";return s[0]?s.before(r):n.append(r),o.append('
            '+(i.content||"")+"
            "),f.hideTabMore(!0),f.tabAuto(),this},s.prototype.tabDelete=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.find('>li[lay-id="'+i+'"]');return f.tabDelete(null,s),this},s.prototype.tabChange=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.find('>li[lay-id="'+i+'"]');return f.tabClick.call(s[0],null,null,s),this},s.prototype.tab=function(t){t=t||{},b.on("click",t.headerElem,function(i){var e=a(this).index();f.tabClick.call(this,i,e,null,t)})},s.prototype.progress=function(t,i){var e="layui-progress",l=a("."+e+"[lay-filter="+t+"]"),n=l.find("."+e+"-bar"),s=n.find("."+e+"-text");return n.css("width",i),s.text(i),this};var o=".layui-nav",r="layui-nav-item",c="layui-nav-bar",u="layui-nav-tree",d="layui-nav-child",y="layui-nav-more",h="layui-anim layui-anim-upbit",f={tabClick:function(t,i,s,o){o=o||{};var r=s||a(this),i=i||r.parent().children("li").index(r),c=o.headerElem?r.parent():r.parents(".layui-tab").eq(0),u=o.bodyElem?a(o.bodyElem):c.children(".layui-tab-content").children(".layui-tab-item"),d=r.find("a"),y=c.attr("lay-filter");"javascript:;"!==d.attr("href")&&"_blank"===d.attr("target")||(r.addClass(l).siblings().removeClass(l),u.eq(i).addClass(n).siblings().removeClass(n)),layui.event.call(this,e,"tab("+y+")",{elem:c,index:i})},tabDelete:function(t,i){var n=i||a(this).parent(),s=n.index(),o=n.parents(".layui-tab").eq(0),r=o.children(".layui-tab-content").children(".layui-tab-item"),c=o.attr("lay-filter");n.hasClass(l)&&(n.next()[0]?f.tabClick.call(n.next()[0],null,s+1):n.prev()[0]&&f.tabClick.call(n.prev()[0],null,s-1)),n.remove(),r.eq(s).remove(),setTimeout(function(){f.tabAuto()},50),layui.event.call(this,e,"tabDelete("+c+")",{elem:o,index:s})},tabAuto:function(){var t="layui-tab-more",e="layui-tab-bar",l="layui-tab-close",n=this;a(".layui-tab").each(function(){var s=a(this),o=s.children(".layui-tab-title"),r=(s.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),c=a('');if(n===window&&8!=i.ie&&f.hideTabMore(!0),s.attr("lay-allowClose")&&o.find("li").each(function(){var t=a(this);if(!t.find("."+l)[0]){var i=a('');i.on("click",f.tabDelete),t.append(i)}}),"string"!=typeof s.attr("lay-unauto"))if(o.prop("scrollWidth")>o.outerWidth()+1){if(o.find("."+e)[0])return;o.append(c),s.attr("overflow",""),c.on("click",function(a){o[this.title?"removeClass":"addClass"](t),this.title=this.title?"":"收缩"})}else o.find("."+e).remove(),s.removeAttr("overflow")})},hideTabMore:function(t){var i=a(".layui-tab-title");t!==!0&&"tabmore"===a(t.target).attr("lay-stope")||(i.removeClass("layui-tab-more"),i.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var t=a(this),i=t.parents(o),n=i.attr("lay-filter"),s=t.parent(),c=t.siblings("."+d),y="string"==typeof s.attr("lay-unselect");"javascript:;"!==t.attr("href")&&"_blank"===t.attr("target")||y||c[0]||(i.find("."+l).removeClass(l),s.addClass(l)),i.hasClass(u)&&(c.removeClass(h),c[0]&&(s["none"===c.css("display")?"addClass":"removeClass"](r+"ed"),"all"===i.attr("lay-shrink")&&s.siblings().removeClass(r+"ed"))),layui.event.call(this,e,"nav("+n+")",t)},collapse:function(){var t=a(this),i=t.find(".layui-colla-icon"),l=t.siblings(".layui-colla-content"),s=t.parents(".layui-collapse").eq(0),o=s.attr("lay-filter"),r="none"===l.css("display");if("string"==typeof s.attr("lay-accordion")){var c=s.children(".layui-colla-item").children("."+n);c.siblings(".layui-colla-title").children(".layui-colla-icon").html(""),c.removeClass(n)}l[r?"addClass":"removeClass"](n),i.html(r?"":""),layui.event.call(this,e,"collapse("+o+")",{title:t,content:l,show:r})}};s.prototype.init=function(t,e){var l=function(){return e?'[lay-filter="'+e+'"]':""}(),s={tab:function(){f.tabAuto.call({})},nav:function(){var t=200,e={},s={},p={},b=function(l,o,r){var c=a(this),f=c.find("."+d);o.hasClass(u)?l.css({top:c.position().top,height:c.children("a").outerHeight(),opacity:1}):(f.addClass(h),l.css({left:c.position().left+parseFloat(c.css("marginLeft")),top:c.position().top+c.height()-l.height()}),e[r]=setTimeout(function(){l.css({width:c.width(),opacity:1})},i.ie&&i.ie<10?0:t),clearTimeout(p[r]),"block"===f.css("display")&&clearTimeout(s[r]),s[r]=setTimeout(function(){f.addClass(n),c.find("."+y).addClass(y+"d")},300))};a(o+l).each(function(i){var l=a(this),o=a(''),h=l.find("."+r);l.find("."+c)[0]||(l.append(o),h.on("mouseenter",function(){b.call(this,o,l,i)}).on("mouseleave",function(){l.hasClass(u)||(clearTimeout(s[i]),s[i]=setTimeout(function(){l.find("."+d).removeClass(n),l.find("."+y).removeClass(y+"d")},300))}),l.on("mouseleave",function(){clearTimeout(e[i]),p[i]=setTimeout(function(){l.hasClass(u)?o.css({height:0,top:o.position().top+o.height()/2,opacity:0}):o.css({width:0,left:o.position().left+o.width()/2,opacity:0})},t)})),h.find("a").each(function(){var t=a(this),i=(t.parent(),t.siblings("."+d));i[0]&&!t.children("."+y)[0]&&t.append(''),t.off("click",f.clickThis).on("click",f.clickThis)})})},breadcrumb:function(){var t=".layui-breadcrumb";a(t+l).each(function(){var t=a(this),i="lay-separator",e=t.attr(i)||"/",l=t.find("a");l.next("span["+i+"]")[0]||(l.each(function(t){t!==l.length-1&&a(this).after(""+e+"")}),t.css("visibility","visible"))})},progress:function(){var t="layui-progress";a("."+t+l).each(function(){var i=a(this),e=i.find(".layui-progress-bar"),l=e.attr("lay-percent");e.css("width",function(){return/^.+\/.+$/.test(l)?100*new Function("return "+l)()+"%":l}()),i.attr("lay-showPercent")&&setTimeout(function(){e.html(''+l+"")},350)})},collapse:function(){var t="layui-collapse";a("."+t+l).each(function(){var t=a(this).find(".layui-colla-item");t.each(function(){var t=a(this),i=t.find(".layui-colla-title"),e=t.find(".layui-colla-content"),l="none"===e.css("display");i.find(".layui-colla-icon").remove(),i.append(''+(l?"":"")+""),i.off("click",f.collapse).on("click",f.collapse)})})}};return s[t]?s[t]():layui.each(s,function(t,a){a()})},s.prototype.render=s.prototype.init;var p=new s,b=a(document);p.render();var v=".layui-tab-title li";b.on("click",v,f.tabClick),b.on("click",f.hideTabMore),a(window).on("resize",f.tabAuto),t(e,p)});layui.define("layer",function(e){"use strict";var t=layui.$,i=layui.layer,n=layui.hint(),o=layui.device(),a={config:{},set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,r,e,t)}},l=function(){var e=this;return{upload:function(t){e.upload.call(e,t)},reload:function(t){e.reload.call(e,t)},config:e.config}},r="upload",u="layui-upload-file",c="layui-upload-form",f="layui-upload-iframe",s="layui-upload-choose",p=function(e){var i=this;i.config=t.extend({},i.config,a.config,e),i.render()};p.prototype.config={accept:"images",exts:"",auto:!0,bindAction:"",url:"",field:"file",acceptMime:"",method:"post",data:{},drag:!0,size:0,number:0,multiple:!1},p.prototype.render=function(e){var i=this,e=i.config;e.elem=t(e.elem),e.bindAction=t(e.bindAction),i.file(),i.events()},p.prototype.file=function(){var e=this,i=e.config,n=e.elemFile=t(['"].join("")),a=i.elem.next();(a.hasClass(u)||a.hasClass(c))&&a.remove(),o.ie&&o.ie<10&&i.elem.wrap('
            '),e.isFile()?(e.elemFile=i.elem,i.field=i.elem[0].name):i.elem.after(n),o.ie&&o.ie<10&&e.initIE()},p.prototype.initIE=function(){var e=this,i=e.config,n=t(''),o=t(['
            ',"
            "].join(""));t("#"+f)[0]||t("body").append(n),i.elem.next().hasClass(c)||(e.elemFile.wrap(o),i.elem.next("."+c).append(function(){var e=[];return layui.each(i.data,function(t,i){i="function"==typeof i?i():i,e.push('')}),e.join("")}()))},p.prototype.msg=function(e){return i.msg(e,{icon:2,shift:6})},p.prototype.isFile=function(){var e=this.config.elem[0];if(e)return"input"===e.tagName.toLocaleLowerCase()&&"file"===e.type},p.prototype.preview=function(e){var t=this;window.FileReader&&layui.each(t.chooseFiles,function(t,i){var n=new FileReader;n.readAsDataURL(i),n.onload=function(){e&&e(t,i,this.result)}})},p.prototype.upload=function(e,i){var n,a=this,l=a.config,r=a.elemFile[0],u=function(){var i=0,n=0,o=e||a.files||a.chooseFiles||r.files,u=function(){l.multiple&&i+n===a.fileLength&&"function"==typeof l.allDone&&l.allDone({total:a.fileLength,successful:i,aborted:n})};layui.each(o,function(e,o){var r=new FormData;r.append(l.field,o),layui.each(l.data,function(e,t){t="function"==typeof t?t():t,r.append(e,t)});var c={url:l.url,type:"post",data:r,contentType:!1,processData:!1,dataType:"json",headers:l.headers||{},success:function(t){i++,d(e,t),u()},error:function(){n++,a.msg("请求上传接口出现异常"),m(e),u()}};"function"==typeof l.progress&&(c.xhr=function(){var e=t.ajaxSettings.xhr();return e.upload.addEventListener("progress",function(e){if(e.lengthComputable){var t=Math.floor(e.loaded/e.total*100);l.progress(t,l.item[0],e)}}),e}),t.ajax(c)})},c=function(){var e=t("#"+f);a.elemFile.parent().submit(),clearInterval(p.timer),p.timer=setInterval(function(){var t,i=e.contents().find("body");try{t=i.text()}catch(n){a.msg("获取上传后的响应信息出现异常"),clearInterval(p.timer),m()}t&&(clearInterval(p.timer),i.html(""),d(0,t))},30)},d=function(e,t){if(a.elemFile.next("."+s).remove(),r.value="","object"!=typeof t)try{t=JSON.parse(t)}catch(i){return t={},a.msg("请对上传接口返回有效JSON")}"function"==typeof l.done&&l.done(t,e||0,function(e){a.upload(e)})},m=function(e){l.auto&&(r.value=""),"function"==typeof l.error&&l.error(e||0,function(e){a.upload(e)})},h=l.exts,v=function(){var t=[];return layui.each(e||a.chooseFiles,function(e,i){t.push(i.name)}),t}(),g={preview:function(e){a.preview(e)},upload:function(e,t){var i={};i[e]=t,a.upload(i)},pushFile:function(){return a.files=a.files||{},layui.each(a.chooseFiles,function(e,t){a.files[e]=t}),a.files},resetFile:function(e,t,i){var n=new File([t],i);a.files=a.files||{},a.files[e]=n}},y=function(){if("choose"!==i&&!l.auto||(l.choose&&l.choose(g),"choose"!==i))return l.before&&l.before(g),o.ie?o.ie>9?u():c():void u()};if(v=0===v.length?r.value.match(/[^\/\\]+\..+/g)||[]||"":v,0!==v.length){switch(l.accept){case"file":if(h&&!RegExp("\\w\\.("+h+")$","i").test(escape(v)))return a.msg("选择的文件中包含不支持的格式"),r.value="";break;case"video":if(!RegExp("\\w\\.("+(h||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(v)))return a.msg("选择的视频中包含不支持的格式"),r.value="";break;case"audio":if(!RegExp("\\w\\.("+(h||"mp3|wav|mid")+")$","i").test(escape(v)))return a.msg("选择的音频中包含不支持的格式"),r.value="";break;default:if(layui.each(v,function(e,t){RegExp("\\w\\.("+(h||"jpg|png|gif|bmp|jpeg$")+")","i").test(escape(t))||(n=!0)}),n)return a.msg("选择的图片中包含不支持的格式"),r.value=""}if(a.fileLength=function(){var t=0,i=e||a.files||a.chooseFiles||r.files;return layui.each(i,function(){t++}),t}(),l.number&&a.fileLength>l.number)return a.msg("同时最多只能上传的数量为:"+l.number);if(l.size>0&&!(o.ie&&o.ie<10)){var F;if(layui.each(a.chooseFiles,function(e,t){if(t.size>1024*l.size){var i=l.size/1024;i=i>=1?i.toFixed(2)+"MB":l.size+"KB",r.value="",F=i}}),F)return a.msg("文件不能超过"+F)}y()}},p.prototype.reload=function(e){e=e||{},delete e.elem,delete e.bindAction;var i=this,e=i.config=t.extend({},i.config,a.config,e),n=e.elem.next();n.attr({name:e.name,accept:e.acceptMime,multiple:e.multiple})},p.prototype.events=function(){var e=this,i=e.config,a=function(t){e.chooseFiles={},layui.each(t,function(t,i){var n=(new Date).getTime();e.chooseFiles[n+"-"+t]=i})},l=function(t,n){var o=e.elemFile,a=t.length>1?t.length+"个文件":(t[0]||{}).name||o[0].value.match(/[^\/\\]+\..+/g)||[]||"";o.next().hasClass(s)&&o.next().remove(),e.upload(null,"choose"),e.isFile()||i.choose||o.after(''+a+"")};i.elem.off("upload.start").on("upload.start",function(){var o=t(this),a=o.attr("lay-data");if(a)try{a=new Function("return "+a)(),e.config=t.extend({},i,a)}catch(l){n.error("Upload element property lay-data configuration item has a syntax error: "+a)}e.config.item=o,e.elemFile[0].click()}),o.ie&&o.ie<10||i.elem.off("upload.over").on("upload.over",function(){var e=t(this);e.attr("lay-over","")}).off("upload.leave").on("upload.leave",function(){var e=t(this);e.removeAttr("lay-over")}).off("upload.drop").on("upload.drop",function(n,o){var r=t(this),u=o.originalEvent.dataTransfer.files||[];r.removeAttr("lay-over"),a(u),i.auto?e.upload(u):l(u)}),e.elemFile.off("upload.change").on("upload.change",function(){var t=this.files||[];a(t),i.auto?e.upload():l(t)}),i.bindAction.off("upload.action").on("upload.action",function(){e.upload()}),i.elem.data("haveEvents")||(e.elemFile.on("change",function(){t(this).trigger("upload.change")}),i.elem.on("click",function(){e.isFile()||t(this).trigger("upload.start")}),i.drag&&i.elem.on("dragover",function(e){e.preventDefault(),t(this).trigger("upload.over")}).on("dragleave",function(e){t(this).trigger("upload.leave")}).on("drop",function(e){e.preventDefault(),t(this).trigger("upload.drop",e)}),i.bindAction.on("click",function(){t(this).trigger("upload.action")}),i.elem.data("haveEvents",!0))},a.render=function(e){var t=new p(e);return l.call(t)},e(r,a)});layui.define(["jquery","laytpl","lay"],function(e){"use strict";var i=layui.$,n=layui.laytpl,t=layui.hint(),a=layui.device(),l=a.mobile?"click":"mousedown",r="dropdown",o="layui_"+r+"_index",u={config:{},index:layui[r]?layui[r].index+1e4:0,set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,r,e,i)}},d=function(){var e=this,i=e.config,n=i.id;return d.that[n]=e,{config:i,reload:function(i){e.reload.call(e,i)}}},s="layui-dropdown",m="layui-menu-item-up",c="layui-menu-item-down",p="layui-menu-body-title",y="layui-menu-item-group",f="layui-menu-item-parent",v="layui-menu-item-divider",g="layui-menu-item-checked",h="layui-menu-item-checked2",w="layui-menu-body-panel",C="layui-menu-body-panel-left",V="."+y+">."+p,k=function(e){var n=this;n.index=++u.index,n.config=i.extend({},n.config,u.config,e),n.init()};k.prototype.config={trigger:"click",content:"",className:"",style:"",show:!1,isAllowSpread:!0,isSpreadItem:!0,data:[],delay:300},k.prototype.reload=function(e){var n=this;n.config=i.extend({},n.config,e),n.init(!0)},k.prototype.init=function(e){var n=this,t=n.config,a=t.elem=i(t.elem);if(a.length>1)return layui.each(a,function(){u.render(i.extend({},t,{elem:this}))}),n;if(!e&&a[0]&&a.data(o)){var l=d.getThis(a.data(o));if(!l)return;return l.reload(t)}t.id="id"in t?t.id:n.index,t.show&&n.render(e),n.events()},k.prototype.render=function(e){var t=this,a=t.config,r=i("body"),s=function(){var e=i('
              ');return a.data.length>0?m(e,a.data):e.html('
            • no menu
            • '),e},m=function(e,t){return layui.each(t,function(t,l){var r=l.child&&l.child.length>0,o="isSpreadItem"in l?l.isSpreadItem:a.isSpreadItem,u=l.templet?n(l.templet).render(l):a.templet?n(a.templet).render(l):l.title,d=function(){return r&&(l.type=l.type||"parent"),l.type?{group:"group",parent:"parent","-":"-"}[l.type]||"parent":""}();if("-"===d||l.title||l.id||r){var s=i(["",function(){var e="href"in l?''+u+"":u;return r?'
              '+e+function(){return"parent"===d?'':"group"===d&&a.isAllowSpread?'':""}()+"
              ":'
              '+e+"
              "}(),""].join(""));if(s.data("item",l),r){var c=i('
              '),y=i("
                ");"parent"===d?(c.append(m(y,l.child)),s.append(c)):s.append(m(y,l.child))}e.append(s)}}),e},c=['
                ',"
                "].join("");("contextmenu"===a.trigger||lay.isTopElem(a.elem[0]))&&(e=!0),!e&&a.elem.data(o+"_opened")||(t.elemView=i(c),t.elemView.append(a.content||s()),a.className&&t.elemView.addClass(a.className),a.style&&t.elemView.attr("style",a.style),u.thisId=a.id,t.remove(),r.append(t.elemView),a.elem.data(o+"_opened",!0),t.position(),d.prevElem=t.elemView,d.prevElem.data("prevElem",a.elem),t.elemView.find(".layui-menu").on(l,function(e){lay.stope(e)}),t.elemView.find(".layui-menu li").on("click",function(e){var n=i(this),l=n.data("item")||{},r=l.child&&l.child.length>0;r||"-"===l.type||(t.remove(),"function"==typeof a.click&&a.click(l,n))}),t.elemView.find(V).on("click",function(e){var n=i(this),t=n.parent(),l=t.data("item")||{};"group"===l.type&&a.isAllowSpread&&d.spread(t)}),"mouseenter"===a.trigger&&t.elemView.on("mouseenter",function(){clearTimeout(d.timer)}).on("mouseleave",function(){t.delayRemove()}))},k.prototype.position=function(e){var i=this,n=i.config;lay.position(n.elem[0],i.elemView[0],{position:n.position,e:i.e,clickType:"contextmenu"===n.trigger?"right":null})},k.prototype.remove=function(){var e=this,i=(e.config,d.prevElem);i&&(i.data("prevElem")&&i.data("prevElem").data(o+"_opened",!1),i.remove())},k.prototype.delayRemove=function(){var e=this,i=e.config;clearTimeout(d.timer),d.timer=setTimeout(function(){e.remove()},i.delay)},k.prototype.events=function(){var e=this,i=e.config;"hover"===i.trigger&&(i.trigger="mouseenter"),e.prevElem&&e.prevElem.off(i.trigger,e.prevElemCallback),e.prevElem=i.elem,e.prevElemCallback=function(n){clearTimeout(d.timer),e.e=n,e.render(),n.preventDefault(),"function"==typeof i.ready&&i.ready(e.elemView,i.elem,e.e.target)},i.elem.on(i.trigger,e.prevElemCallback),"mouseenter"===i.trigger&&i.elem.on("mouseleave",function(){e.delayRemove()})},d.that={},d.getThis=function(e){var i=d.that[e];return i||t.error(e?r+" instance with ID '"+e+"' not found":"ID argument required"),i},d.spread=function(e){var i=e.children("."+p).find(".layui-icon");e.hasClass(m)?(e.removeClass(m).addClass(c),i.removeClass("layui-icon-down").addClass("layui-icon-up")):(e.removeClass(c).addClass(m),i.removeClass("layui-icon-up").addClass("layui-icon-down"))},!function(){var e=i(window),n=i(document);e.on("resize",function(){if(u.thisId){var e=d.getThis(u.thisId);if(e){if(!e.elemView[0]||!i("."+s)[0])return!1;var n=e.config;"contextmenu"===n.trigger?e.remove():e.position()}}}),n.on(l,function(e){if(u.thisId){var i=d.getThis(u.thisId);if(i){var n=i.config;!lay.isTopElem(n.elem[0])&&"contextmenu"!==n.trigger&&(e.target===n.elem[0]||n.elem.find(e.target)[0]||e.target===i.elemView[0]||i.elemView&&i.elemView.find(e.target)[0])||i.remove()}}});var t=".layui-menu:not(.layui-dropdown-menu) li";n.on("click",t,function(e){var n=i(this),t=n.parents(".layui-menu").eq(0),a=n.hasClass(y)||n.hasClass(f),l=t.attr("lay-filter")||t.attr("id"),o=lay.options(this);n.hasClass(v)||a||(t.find("."+g).removeClass(g),t.find("."+h).removeClass(h),n.addClass(g),n.parents("."+f).addClass(h),layui.event.call(this,r,"click("+l+")",o))}),n.on("click",t+V,function(e){var n=i(this),t=n.parents("."+y+":eq(0)"),a=lay.options(t[0]);"isAllowSpread"in a&&!a.isAllowSpread||d.spread(t)});var a=".layui-menu ."+f;n.on("mouseenter",a,function(n){var t=i(this),a=t.find("."+w);if(a[0]){var l=a[0].getBoundingClientRect();l.right>e.width()&&(a.addClass(C),l=a[0].getBoundingClientRect(),l.left<0&&a.removeClass(C)),l.bottom>e.height()&&a.eq(0).css("margin-top",-(l.bottom-e.height()))}}).on("mouseleave",a,function(e){var n=i(this),t=n.children("."+w);t.removeClass(C),t.css("margin-top",0)})}(),u.reload=function(e,i){var n=d.getThis(e);return n?(n.reload(i),d.call(n)):this},u.render=function(e){var i=new k(e);return d.call(i)},e(r,u)});layui.define("jquery",function(e){"use strict";var i=layui.jquery,t={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var t=this;return t.config=i.extend({},t.config,e),t},on:function(e,i){return layui.onevent.call(this,n,e,i)}},a=function(){var e=this,i=e.config;return{setValue:function(t,a){return i.value=t,e.slide("set",t,a||0)},config:i}},n="slider",l="layui-disabled",s="layui-slider",r="layui-slider-bar",o="layui-slider-wrap",u="layui-slider-wrap-btn",d="layui-slider-tips",v="layui-slider-input",c="layui-slider-input-txt",p="layui-slider-input-btn",m="layui-slider-hover",f=function(e){var a=this;a.index=++t.index,a.config=i.extend({},a.config,t.config,e),a.render()};f.prototype.config={type:"default",min:0,max:100,value:0,step:1,showstep:!1,tips:!0,input:!1,range:!1,height:200,disabled:!1,theme:"#009688"},f.prototype.render=function(){var e=this,t=e.config;if(t.step<1&&(t.step=1),t.maxt.min?a:t.min,t.value[1]=n>t.min?n:t.min,t.value[0]=t.value[0]>t.max?t.max:t.value[0],t.value[1]=t.value[1]>t.max?t.max:t.value[1];var r=Math.floor((t.value[0]-t.min)/(t.max-t.min)*100),v=Math.floor((t.value[1]-t.min)/(t.max-t.min)*100),p=v-r+"%";r+="%",v+="%"}else{"object"==typeof t.value&&(t.value=Math.min.apply(null,t.value)),t.valuet.max&&(t.value=t.max);var p=Math.floor((t.value-t.min)/(t.max-t.min)*100)+"%"}var m=t.disabled?"#c2c2c2":t.theme,f='
                '+(t.tips?'
                ':"")+'
                '+(t.range?'
                ':"")+"
                ",h=i(t.elem),y=h.next("."+s);if(y[0]&&y.remove(),e.elemTemp=i(f),t.range?(e.elemTemp.find("."+o).eq(0).data("value",t.value[0]),e.elemTemp.find("."+o).eq(1).data("value",t.value[1])):e.elemTemp.find("."+o).data("value",t.value),h.html(e.elemTemp),"vertical"===t.type&&e.elemTemp.height(t.height+"px"),t.showstep){for(var g=(t.max-t.min)/t.step,b="",x=1;x
                ')}e.elemTemp.append(b)}if(t.input&&!t.range){var w=i('
                ');h.css("position","relative"),h.append(w),h.find("."+c).children("input").val(t.value),"vertical"===t.type?w.css({left:0,top:-48}):e.elemTemp.css("margin-right",w.outerWidth()+15)}t.disabled?(e.elemTemp.addClass(l),e.elemTemp.find("."+u).addClass(l)):e.slide(),e.elemTemp.find("."+u).on("mouseover",function(){var a="vertical"===t.type?t.height:e.elemTemp[0].offsetWidth,n=e.elemTemp.find("."+o),l="vertical"===t.type?a-i(this).parent()[0].offsetTop-n.height():i(this).parent()[0].offsetLeft,s=l/a*100,r=i(this).parent().data("value"),u=t.setTips?t.setTips(r):r;e.elemTemp.find("."+d).html(u),"vertical"===t.type?e.elemTemp.find("."+d).css({bottom:s+"%","margin-bottom":"20px",display:"inline-block"}):e.elemTemp.find("."+d).css({left:s+"%",display:"inline-block"})}).on("mouseout",function(){e.elemTemp.find("."+d).css("display","none")})},f.prototype.slide=function(e,t,a){var n=this,l=n.config,s=n.elemTemp,f=function(){return"vertical"===l.type?l.height:s[0].offsetWidth},h=s.find("."+o),y=s.next("."+v),g=y.children("."+c).children("input").val(),b=100/((l.max-l.min)/Math.ceil(l.step)),x=function(e,i){e=Math.ceil(e)*b>100?Math.ceil(e)*b:Math.round(e)*b,e=e>100?100:e,h.eq(i).css("vertical"===l.type?"bottom":"left",e+"%");var t=T(h[0].offsetLeft),a=l.range?T(h[1].offsetLeft):0;"vertical"===l.type?(s.find("."+d).css({bottom:e+"%","margin-bottom":"20px"}),t=T(f()-h[0].offsetTop-h.height()),a=l.range?T(f()-h[1].offsetTop-h.height()):0):s.find("."+d).css("left",e+"%"),t=t>100?100:t,a=a>100?100:a;var n=Math.min(t,a),o=Math.abs(t-a);"vertical"===l.type?s.find("."+r).css({height:o+"%",bottom:n+"%"}):s.find("."+r).css({width:o+"%",left:n+"%"});var u=l.min+Math.round((l.max-l.min)*e/100);if(g=u,y.children("."+c).children("input").val(g),h.eq(i).data("value",u),s.find("."+d).html(l.setTips?l.setTips(u):u),l.range){var v=[h.eq(0).data("value"),h.eq(1).data("value")];v[0]>v[1]&&v.reverse()}l.change&&l.change(l.range?v:u)},T=function(e){var i=e/f()*100/b,t=Math.round(i)*b;return e==f()&&(t=Math.ceil(i)*b),t},w=i(['
                f()&&(r=f());var o=r/f()*100/b;x(o,e),t.addClass(m),s.find("."+d).show(),i.preventDefault()},o=function(){t.removeClass(m),s.find("."+d).hide()};M(r,o)})}),s.on("click",function(e){var t=i("."+u);if(!t.is(event.target)&&0===t.has(event.target).length&&t.length){var a,n="vertical"===l.type?f()-e.clientY+i(this).offset().top:e.clientX-i(this).offset().left;n<0&&(n=0),n>f()&&(n=f());var s=n/f()*100/b;a=l.range?"vertical"===l.type?Math.abs(n-parseInt(i(h[0]).css("bottom")))>Math.abs(n-parseInt(i(h[1]).css("bottom")))?1:0:Math.abs(n-h[0].offsetLeft)>Math.abs(n-h[1].offsetLeft)?1:0:0,x(s,a),e.preventDefault()}}),y.children("."+p).children("i").each(function(e){i(this).on("click",function(){g=y.children("."+c).children("input").val(),g=1==e?g-l.stepl.max?l.max:Number(g)+l.step;var i=(g-l.min)/(l.max-l.min)*100/b;x(i,0)})});var q=function(){var e=this.value;e=isNaN(e)?0:e,e=el.max?l.max:e,this.value=e;var i=(e-l.min)/(l.max-l.min)*100/b;x(i,0)};y.children("."+c).children("input").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),q.call(this))}).on("change",q)},f.prototype.events=function(){var e=this;e.config},t.render=function(e){var i=new f(e);return a.call(i)},e(n,t)});layui.define("jquery",function(e){"use strict";var i=layui.jquery,o={config:{},index:layui.colorpicker?layui.colorpicker.index+1e4:0,set:function(e){var o=this;return o.config=i.extend({},o.config,e),o},on:function(e,i){return layui.onevent.call(this,"colorpicker",e,i)}},r=function(){var e=this,i=e.config;return{config:i}},t="colorpicker",n="layui-show",l="layui-colorpicker",c=".layui-colorpicker-main",a="layui-icon-down",s="layui-icon-close",f="layui-colorpicker-trigger-span",d="layui-colorpicker-trigger-i",u="layui-colorpicker-side",p="layui-colorpicker-side-slider",g="layui-colorpicker-basis",v="layui-colorpicker-alpha-bgcolor",h="layui-colorpicker-alpha-slider",m="layui-colorpicker-basis-cursor",b="layui-colorpicker-main-input",k=function(e){var i={h:0,s:0,b:0},o=Math.min(e.r,e.g,e.b),r=Math.max(e.r,e.g,e.b),t=r-o;return i.b=r,i.s=0!=r?255*t/r:0,0!=i.s?e.r==r?i.h=(e.g-e.b)/t:e.g==r?i.h=2+(e.b-e.r)/t:i.h=4+(e.r-e.g)/t:i.h=-1,r==o&&(i.h=0),i.h*=60,i.h<0&&(i.h+=360),i.s*=100/255,i.b*=100/255,i},y=function(e){var e=e.indexOf("#")>-1?e.substring(1):e;if(3==e.length){var i=e.split("");e=i[0]+i[0]+i[1]+i[1]+i[2]+i[2]}e=parseInt(e,16);var o={r:e>>16,g:(65280&e)>>8,b:255&e};return k(o)},x=function(e){var i={},o=e.h,r=255*e.s/100,t=255*e.b/100;if(0==r)i.r=i.g=i.b=t;else{var n=t,l=(255-r)*t/255,c=(n-l)*(o%60)/60;360==o&&(o=0),o<60?(i.r=n,i.b=l,i.g=l+c):o<120?(i.g=n,i.b=l,i.r=n-c):o<180?(i.g=n,i.r=l,i.b=l+c):o<240?(i.b=n,i.r=l,i.g=n-c):o<300?(i.b=n,i.g=l,i.r=l+c):o<360?(i.r=n,i.g=l,i.b=n-c):(i.r=0,i.g=0,i.b=0)}return{r:Math.round(i.r),g:Math.round(i.g),b:Math.round(i.b)}},C=function(e){var o=x(e),r=[o.r.toString(16),o.g.toString(16),o.b.toString(16)];return i.each(r,function(e,i){1==i.length&&(r[e]="0"+i)}),r.join("")},P=function(e){var i=/[0-9]{1,3}/g,o=e.match(i)||[];return{r:o[0],g:o[1],b:o[2]}},B=i(window),w=i(document),D=function(e){var r=this;r.index=++o.index,r.config=i.extend({},r.config,o.config,e),r.render()};D.prototype.config={color:"",size:null,alpha:!1,format:"hex",predefine:!1,colors:["#009688","#5FB878","#1E9FFF","#FF5722","#FFB800","#01AAED","#999","#c00","#ff8c00","#ffd700","#90ee90","#00ced1","#1e90ff","#c71585","rgb(0, 186, 189)","rgb(255, 120, 0)","rgb(250, 212, 0)","#393D49","rgba(0,0,0,.5)","rgba(255, 69, 0, 0.68)","rgba(144, 240, 144, 0.5)","rgba(31, 147, 255, 0.73)"]},D.prototype.render=function(){var e=this,o=e.config,r=i(['
                ',"",'3&&(o.alpha&&"rgb"==o.format||(e="#"+C(k(P(o.color))))),"background: "+e):e}()+'">','',"","","
                "].join("")),t=i(o.elem);o.size&&r.addClass("layui-colorpicker-"+o.size),t.addClass("layui-inline").html(e.elemColorBox=r),e.color=e.elemColorBox.find("."+f)[0].style.background,e.events()},D.prototype.renderPicker=function(){var e=this,o=e.config,r=e.elemColorBox[0],t=e.elemPicker=i(['
                ','
                ','
                ','
                ','
                ','
                ',"
                ",'
                ','
                ',"
                ","
                ",'
                ','
                ','
                ',"
                ","
                ",function(){if(o.predefine){var e=['
                '];return layui.each(o.colors,function(i,o){e.push(['
                ','
                ',"
                "].join(""))}),e.push("
                "),e.join("")}return""}(),'
                ','
                ','',"
                ",'
                ','','',"","
                "].join(""));e.elemColorBox.find("."+f)[0];i(c)[0]&&i(c).data("index")==e.index?e.removePicker(D.thisElemInd):(e.removePicker(D.thisElemInd),i("body").append(t)),D.thisElemInd=e.index,D.thisColor=r.style.background,e.position(),e.pickerEvents()},D.prototype.removePicker=function(e){var o=this;o.config;return i("#layui-colorpicker"+(e||o.index)).remove(),o},D.prototype.position=function(){var e=this,i=e.config,o=e.bindElem||e.elemColorBox[0],r=e.elemPicker[0],t=o.getBoundingClientRect(),n=r.offsetWidth,l=r.offsetHeight,c=function(e){return e=e?"scrollLeft":"scrollTop",document.body[e]|document.documentElement[e]},a=function(e){return document.documentElement[e?"clientWidth":"clientHeight"]},s=5,f=t.left,d=t.bottom;f-=(n-o.offsetWidth)/2,d+=s,f+n+s>a("width")?f=a("width")-n-s:fa()&&(d=t.top>l?t.top-l:a()-l,d-=2*s),i.position&&(r.style.position=i.position),r.style.left=f+("fixed"===i.position?0:c(1))+"px",r.style.top=d+("fixed"===i.position?0:c())+"px"},D.prototype.val=function(){var e=this,i=(e.config,e.elemColorBox.find("."+f)),o=e.elemPicker.find("."+b),r=i[0],t=r.style.backgroundColor;if(t){var n=k(P(t)),l=i.attr("lay-type");if(e.select(n.h,n.s,n.b),"torgb"===l&&o.find("input").val(t),"rgba"===l){var c=P(t);if(3==(t.match(/[0-9]{1,3}/g)||[]).length)o.find("input").val("rgba("+c.r+", "+c.g+", "+c.b+", 1)"),e.elemPicker.find("."+h).css("left",280);else{o.find("input").val(t);var a=280*t.slice(t.lastIndexOf(",")+1,t.length-1);e.elemPicker.find("."+h).css("left",a)}e.elemPicker.find("."+v)[0].style.background="linear-gradient(to right, rgba("+c.r+", "+c.g+", "+c.b+", 0), rgb("+c.r+", "+c.g+", "+c.b+"))"}}else e.select(0,100,100),o.find("input").val(""),e.elemPicker.find("."+v)[0].style.background="",e.elemPicker.find("."+h).css("left",280)},D.prototype.side=function(){var e=this,o=e.config,r=e.elemColorBox.find("."+f),t=r.attr("lay-type"),n=e.elemPicker.find("."+u),l=e.elemPicker.find("."+p),c=e.elemPicker.find("."+g),y=e.elemPicker.find("."+m),C=e.elemPicker.find("."+v),w=e.elemPicker.find("."+h),D=l[0].offsetTop/180*360,E=100-(y[0].offsetTop+3)/180*100,H=(y[0].offsetLeft+3)/260*100,W=Math.round(w[0].offsetLeft/280*100)/100,j=e.elemColorBox.find("."+d),F=e.elemPicker.find(".layui-colorpicker-pre").children("div"),L=function(i,n,l,c){e.select(i,n,l);var f=x({h:i,s:n,b:l});if(j.addClass(a).removeClass(s),r[0].style.background="rgb("+f.r+", "+f.g+", "+f.b+")","torgb"===t&&e.elemPicker.find("."+b).find("input").val("rgb("+f.r+", "+f.g+", "+f.b+")"),"rgba"===t){var d=0;d=280*c,w.css("left",d),e.elemPicker.find("."+b).find("input").val("rgba("+f.r+", "+f.g+", "+f.b+", "+c+")"),r[0].style.background="rgba("+f.r+", "+f.g+", "+f.b+", "+c+")",C[0].style.background="linear-gradient(to right, rgba("+f.r+", "+f.g+", "+f.b+", 0), rgb("+f.r+", "+f.g+", "+f.b+"))"}o.change&&o.change(e.elemPicker.find("."+b).find("input").val())},M=i(['
                t&&(r=t);var l=r/180*360;D=l,L(l,H,E,W),e.preventDefault()};Y(r),e.preventDefault()}),n.on("click",function(e){var o=e.clientY-i(this).offset().top;o<0&&(o=0),o>this.offsetHeight&&(o=this.offsetHeight);var r=o/180*360;D=r,L(r,H,E,W),e.preventDefault()}),y.on("mousedown",function(e){var i=this.offsetTop,o=this.offsetLeft,r=e.clientY,t=e.clientX,n=function(e){var n=i+(e.clientY-r),l=o+(e.clientX-t),a=c[0].offsetHeight-3,s=c[0].offsetWidth-3;n<-3&&(n=-3),n>a&&(n=a),l<-3&&(l=-3),l>s&&(l=s);var f=(l+3)/260*100,d=100-(n+3)/180*100;E=d,H=f,L(D,f,d,W),e.preventDefault()};layui.stope(e),Y(n),e.preventDefault()}),c.on("mousedown",function(e){var o=e.clientY-i(this).offset().top-3+B.scrollTop(),r=e.clientX-i(this).offset().left-3+B.scrollLeft();o<-3&&(o=-3),o>this.offsetHeight-3&&(o=this.offsetHeight-3),r<-3&&(r=-3),r>this.offsetWidth-3&&(r=this.offsetWidth-3);var t=(r+3)/260*100,n=100-(o+3)/180*100;E=n,H=t,L(D,t,n,W),e.preventDefault(),y.trigger(e,"mousedown")}),w.on("mousedown",function(e){var i=this.offsetLeft,o=e.clientX,r=function(e){var r=i+(e.clientX-o),t=C[0].offsetWidth;r<0&&(r=0),r>t&&(r=t);var n=Math.round(r/280*100)/100;W=n,L(D,H,E,n),e.preventDefault()};Y(r),e.preventDefault()}),C.on("click",function(e){var o=e.clientX-i(this).offset().left;o<0&&(o=0),o>this.offsetWidth&&(o=this.offsetWidth);var r=Math.round(o/280*100)/100;W=r,L(D,H,E,r),e.preventDefault()}),F.each(function(){i(this).on("click",function(){i(this).parent(".layui-colorpicker-pre").addClass("selected").siblings().removeClass("selected");var e,o=this.style.backgroundColor,r=k(P(o)),t=o.slice(o.lastIndexOf(",")+1,o.length-1);D=r.h,H=r.s,E=r.b,3==(o.match(/[0-9]{1,3}/g)||[]).length&&(t=1),W=t,e=280*t,L(r.h,r.s,r.b,t)})})},D.prototype.select=function(e,i,o,r){var t=this,n=(t.config,C({h:e,s:100,b:100})),l=C({h:e,s:i,b:o}),c=e/360*180,a=180-o/100*180-3,s=i/100*260-3;t.elemPicker.find("."+p).css("top",c),t.elemPicker.find("."+g)[0].style.background="#"+n,t.elemPicker.find("."+m).css({top:a,left:s}),"change"!==r&&t.elemPicker.find("."+b).find("input").val("#"+l)},D.prototype.pickerEvents=function(){var e=this,o=e.config,r=e.elemColorBox.find("."+f),t=e.elemPicker.find("."+b+" input"),n={clear:function(i){r[0].style.background="",e.elemColorBox.find("."+d).removeClass(a).addClass(s),e.color="",o.done&&o.done(""),e.removePicker()},confirm:function(i,n){var l=t.val(),c=l,f={};if(l.indexOf(",")>-1){if(f=k(P(l)),e.select(f.h,f.s,f.b),r[0].style.background=c="#"+C(f),(l.match(/[0-9]{1,3}/g)||[]).length>3&&"rgba"===r.attr("lay-type")){var u=280*l.slice(l.lastIndexOf(",")+1,l.length-1);e.elemPicker.find("."+h).css("left",u),r[0].style.background=l,c=l}}else f=y(l),r[0].style.background=c="#"+C(f),e.elemColorBox.find("."+d).removeClass(s).addClass(a);return"change"===n?(e.select(f.h,f.s,f.b,n),void(o.change&&o.change(c))):(e.color=l,o.done&&o.done(l),void e.removePicker())}};e.elemPicker.on("click","*[colorpicker-events]",function(){var e=i(this),o=e.attr("colorpicker-events");n[o]&&n[o].call(this,e)}),t.on("keyup",function(e){var o=i(this);n.confirm.call(this,o,13===e.keyCode?null:"change")})},D.prototype.events=function(){var e=this,o=e.config,r=e.elemColorBox.find("."+f);e.elemColorBox.on("click",function(){e.renderPicker(),i(c)[0]&&(e.val(),e.side())}),o.elem[0]&&!e.elemColorBox[0].eventHandler&&(w.on("click",function(o){if(!i(o.target).hasClass(l)&&!i(o.target).parents("."+l)[0]&&!i(o.target).hasClass(c.replace(/\./g,""))&&!i(o.target).parents(c)[0]&&e.elemPicker){if(e.color){var t=k(P(e.color));e.select(t.h,t.s,t.b)}else e.elemColorBox.find("."+d).removeClass(a).addClass(s);r[0].style.background=e.color||"",e.removePicker()}}),B.on("resize",function(){return!(!e.elemPicker||!i(c)[0])&&void e.position()}),e.elemColorBox[0].eventHandler=!0)},o.render=function(e){var i=new D(e);return r.call(i)},e(t,o)});layui.define("layer",function(e){"use strict";var t=layui.$,i=layui.layer,a=layui.hint(),n=layui.device(),l="form",r=".layui-form",s="layui-this",o="layui-hide",c="layui-disabled",u=function(){this.config={verify:{required:[/[\S]+/,"必填项不能为空"],phone:[/^1\d{10}$/,"请输入正确的手机号"],email:[/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,"邮箱格式不正确"],url:[/(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/,"链接格式不正确"],number:function(e){if(!e||isNaN(e))return"只能填写数字"},date:[/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/,"日期格式不正确"],identity:[/(^\d{15}$)|(^\d{17}(x|X|\d)$)/,"请输入正确的身份证号"]}}};u.prototype.set=function(e){var i=this;return t.extend(!0,i.config,e),i},u.prototype.verify=function(e){var i=this;return t.extend(!0,i.config.verify,e),i},u.prototype.on=function(e,t){return layui.onevent.call(this,l,e,t)},u.prototype.val=function(e,i){var a=this,n=t(r+'[lay-filter="'+e+'"]');return n.each(function(e,a){var n=t(this);layui.each(i,function(e,t){var i,a=n.find('[name="'+e+'"]');a[0]&&(i=a[0].type,"checkbox"===i?a[0].checked=t:"radio"===i?a.each(function(){this.value==t&&(this.checked=!0)}):a.val(t))})}),f.render(null,e),a.getValue(e)},u.prototype.getValue=function(e,i){i=i||t(r+'[lay-filter="'+e+'"]').eq(0);var a={},n={},l=i.find("input,select,textarea");return layui.each(l,function(e,t){if(t.name=(t.name||"").replace(/^\s*|\s*&/,""),t.name){if(/^.*\[\]$/.test(t.name)){var i=t.name.match(/^(.*)\[\]$/g)[0];a[i]=0|a[i],t.name=t.name.replace(/^(.*)\[\]$/,"$1["+a[i]++ +"]")}/^checkbox|radio$/.test(t.type)&&!t.checked||(n[t.name]=t.value)}}),n},u.prototype.render=function(e,i){var n=this,u=t(r+function(){return i?'[lay-filter="'+i+'"]':""}()),d={select:function(){var e,i="请选择",a="layui-form-select",n="layui-select-title",r="layui-select-none",d="",f=u.find("select"),v=function(i,l){t(i.target).parent().hasClass(n)&&!l||(t("."+a).removeClass(a+"ed "+a+"up"),e&&d&&e.val(d)),e=null},y=function(i,u,f){var y,p=t(this),m=i.find("."+n),k=m.find("input"),g=i.find("dl"),x=g.children("dd"),b=this.selectedIndex;if(!u){var C=function(){var e=i.offset().top+i.outerHeight()+5-h.scrollTop(),t=g.outerHeight();b=p[0].selectedIndex,i.addClass(a+"ed"),x.removeClass(o),y=null,x.eq(b).addClass(s).siblings().removeClass(s),e+t>h.height()&&e>=t&&i.addClass(a+"up"),T()},w=function(e){i.removeClass(a+"ed "+a+"up"),k.blur(),y=null,e||$(k.val(),function(e){var i=p[0].selectedIndex;e&&(d=t(p[0].options[i]).html(),0===i&&d===k.attr("placeholder")&&(d=""),k.val(d||""))})},T=function(){var e=g.children("dd."+s);if(e[0]){var t=e.position().top,i=g.height(),a=e.height();t>i&&g.scrollTop(t+g.scrollTop()-i+a-5),t<0&&g.scrollTop(t+g.scrollTop()-5)}};m.on("click",function(e){i.hasClass(a+"ed")?w():(v(e,!0),C()),g.find("."+r).remove()}),m.find(".layui-edge").on("click",function(){k.focus()}),k.on("keyup",function(e){var t=e.keyCode;9===t&&C()}).on("keydown",function(e){var t=e.keyCode;9===t&&w();var i=function(t,a){var n,l;e.preventDefault();var r=function(){var e=g.children("dd."+s);if(g.children("dd."+o)[0]&&"next"===t){var i=g.children("dd:not(."+o+",."+c+")"),n=i.eq(0).index();if(n>=0&&n无匹配项

                '):g.find("."+r).remove()},"keyup"),""===t&&g.find("."+r).remove(),void T())};f&&k.on("keyup",q).on("blur",function(i){var a=p[0].selectedIndex;e=k,d=t(p[0].options[a]).html(),0===a&&d===k.attr("placeholder")&&(d=""),setTimeout(function(){$(k.val(),function(e){d||k.val("")},"blur")},200)}),x.on("click",function(){var e=t(this),a=e.attr("lay-value"),n=p.attr("lay-filter");return!e.hasClass(c)&&(e.hasClass("layui-select-tips")?k.val(""):(k.val(e.text()),e.addClass(s)),e.siblings().removeClass(s),p.val(a).removeClass("layui-form-danger"),layui.event.call(this,l,"select("+n+")",{elem:p[0],value:a,othis:i}),w(!0),!1)}),i.find("dl>dt").on("click",function(e){return!1}),t(document).off("click",v).on("click",v)}};f.each(function(e,l){var r=t(this),o=r.next("."+a),u=this.disabled,d=l.value,f=t(l.options[l.selectedIndex]),v=l.options[0];if("string"==typeof r.attr("lay-ignore"))return r.show();var h="string"==typeof r.attr("lay-search"),p=v?v.value?i:v.innerHTML||i:i,m=t(['
                ','
                ','','
                ','
                ',function(e){var t=[];return layui.each(e,function(e,a){0!==e||a.value?"optgroup"===a.tagName.toLowerCase()?t.push("
                "+a.label+"
                "):t.push('
                '+a.innerHTML+"
                "):t.push('
                '+(a.innerHTML||i)+"
                ")}),0===t.length&&t.push('
                没有选项
                '),t.join("")}(r.find("*"))+"
                ","
                "].join(""));o[0]&&o.remove(),r.after(m),y.call(this,m,u,h)})},checkbox:function(){var e={checkbox:["layui-form-checkbox","layui-form-checked","checkbox"],_switch:["layui-form-switch","layui-form-onswitch","switch"]},i=u.find("input[type=checkbox]"),a=function(e,i){var a=t(this);e.on("click",function(){var t=a.attr("lay-filter"),n=(a.attr("lay-text")||"").split("|");a[0].disabled||(a[0].checked?(a[0].checked=!1,e.removeClass(i[1]).find("em").text(n[1])):(a[0].checked=!0,e.addClass(i[1]).find("em").text(n[0])),layui.event.call(a[0],l,i[2]+"("+t+")",{elem:a[0],value:a[0].value,othis:e}))})};i.each(function(i,n){var l=t(this),r=l.attr("lay-skin"),s=(l.attr("lay-text")||"").split("|"),o=this.disabled;"switch"===r&&(r="_"+r);var u=e[r]||e.checkbox;if("string"==typeof l.attr("lay-ignore"))return l.show();var d=l.next("."+u[0]),f=t(['
                ",function(){var e=n.title.replace(/\s/g,""),t={checkbox:[e?""+n.title+"":"",''].join(""),_switch:""+((n.checked?s[0]:s[1])||"")+""};return t[r]||t.checkbox}(),"
                "].join(""));d[0]&&d.remove(),l.after(f),a.call(this,f,u)})},radio:function(){var e="layui-form-radio",i=["",""],a=u.find("input[type=radio]"),n=function(a){var n=t(this),s="layui-anim-scaleSpring";a.on("click",function(){var o=n[0].name,c=n.parents(r),u=n.attr("lay-filter"),d=c.find("input[name="+o.replace(/(\.|#|\[|\])/g,"\\$1")+"]");n[0].disabled||(layui.each(d,function(){var a=t(this).next("."+e);this.checked=!1,a.removeClass(e+"ed"),a.find(".layui-icon").removeClass(s).html(i[1])}),n[0].checked=!0,a.addClass(e+"ed"),a.find(".layui-icon").addClass(s).html(i[0]),layui.event.call(n[0],l,"radio("+u+")",{elem:n[0],value:n[0].value,othis:a}))})};a.each(function(a,l){var r=t(this),s=r.next("."+e),o=this.disabled;if("string"==typeof r.attr("lay-ignore"))return r.show();s[0]&&s.remove();var u=t(['
                ',''+i[l.checked?0:1]+"","
                "+function(){var e=l.title||"";return"string"==typeof r.next().attr("lay-radio")&&(e=r.next().html(),r.next().remove()),e}()+"
                ","
                "].join(""));r.after(u),n.call(this,u)})}};return e?d[e]?d[e]():a.error("不支持的"+e+"表单渲染"):layui.each(d,function(e,t){t()}),n};var d=function(){var e=null,a=f.config.verify,s="layui-form-danger",o={},c=t(this),u=c.parents(r),d=u.find("*[lay-verify]"),v=c.parents("form")[0],h=c.attr("lay-filter");return layui.each(d,function(l,r){var o=t(this),c=o.attr("lay-verify").split("|"),u=o.attr("lay-verType"),d=o.val();if(o.removeClass(s),layui.each(c,function(t,l){var c,f="",v="function"==typeof a[l];if(a[l]){var c=v?f=a[l](d,r):!a[l][0].test(d);if(f=f||a[l][1],"required"===l&&(f=o.attr("lay-reqText")||f),c)return"tips"===u?i.tips(f,function(){return"string"==typeof o.attr("lay-ignore")||"select"!==r.tagName.toLowerCase()&&!/^checkbox|radio$/.test(r.type)?o:o.next()}(),{tips:1}):"alert"===u?i.alert(f,{title:"提示",shadeClose:!0}):/\bstring|number\b/.test(typeof f)&&i.msg(f,{icon:5,shift:6}),n.android||n.ios||setTimeout(function(){r.focus()},7),o.addClass(s),e=!0}}),e)return e}),!e&&(o=f.getValue(null,u),layui.event.call(this,l,"submit("+h+")",{elem:this,form:v,field:o}))},f=new u,v=t(document),h=t(window);f.render(),v.on("reset",r,function(){var e=t(this).attr("lay-filter");setTimeout(function(){f.render(null,e)},50)}),v.on("submit",r,d).on("click","*[lay-submit]",d),e(l,f)});layui.define("form",function(e){"use strict";var i=layui.$,a=layui.form,n=layui.layer,t="tree",r={config:{},index:layui[t]?layui[t].index+1e4:0,set:function(e){var a=this;return a.config=i.extend({},a.config,e),a},on:function(e,i){return layui.onevent.call(this,t,e,i)}},l=function(){var e=this,i=e.config,a=i.id||e.index;return l.that[a]=e,l.config[a]=i,{config:i,reload:function(i){e.reload.call(e,i)},getChecked:function(){return e.getChecked.call(e)},setChecked:function(i){return e.setChecked.call(e,i)}}},c="layui-hide",d="layui-disabled",s="layui-tree-set",o="layui-tree-iconClick",h="layui-icon-addition",u="layui-icon-subtraction",p="layui-tree-entry",f="layui-tree-main",y="layui-tree-txt",v="layui-tree-pack",C="layui-tree-spread",k="layui-tree-setLineShort",m="layui-tree-showLine",x="layui-tree-lineExtend",b=function(e){var a=this;a.index=++r.index,a.config=i.extend({},a.config,r.config,e),a.render()};b.prototype.config={data:[],showCheckbox:!1,showLine:!0,accordion:!1,onlyIconControl:!1,isJump:!1,edit:!1,text:{defaultNodeName:"未命名",none:"无数据"}},b.prototype.reload=function(e){var a=this;layui.each(e,function(e,i){i.constructor===Array&&delete a.config[e]}),a.config=i.extend(!0,{},a.config,e),a.render()},b.prototype.render=function(){var e=this,a=e.config;e.checkids=[];var n=i('
                ');e.tree(n);var t=a.elem=i(a.elem);if(t[0]){if(e.key=a.id||e.index,e.elem=n,e.elemNone=i('
                '+a.text.none+"
                "),t.html(e.elem),0==e.elem.find(".layui-tree-set").length)return e.elem.append(e.elemNone);a.showCheckbox&&e.renderForm("checkbox"),e.elem.find(".layui-tree-set").each(function(){var e=i(this);e.parent(".layui-tree-pack")[0]||e.addClass("layui-tree-setHide"),!e.next()[0]&&e.parents(".layui-tree-pack").eq(1).hasClass("layui-tree-lineExtend")&&e.addClass(k),e.next()[0]||e.parents(".layui-tree-set").eq(0).next()[0]||e.addClass(k)}),e.events()}},b.prototype.renderForm=function(e){a.render(e,"LAY-tree-"+this.index)},b.prototype.tree=function(e,a){var n=this,t=n.config,r=a||t.data;layui.each(r,function(a,r){var l=r.children&&r.children.length>0,o=i('
                "),h=i(['
                ','
                ','
                ',function(){return t.showLine?l?'':'':''}(),function(){return t.showCheckbox?'':""}(),function(){return t.isJump&&r.href?''+(r.title||r.label||t.text.defaultNodeName)+"":''+(r.title||r.label||t.text.defaultNodeName)+""}(),"
                ",function(){if(!t.edit)return"";var e={add:'',update:'',del:''},i=['
                '];return t.edit===!0&&(t.edit=["update","del"]),"object"==typeof t.edit?(layui.each(t.edit,function(a,n){i.push(e[n]||"")}),i.join("")+"
                "):void 0}(),"
                "].join(""));l&&(h.append(o),n.tree(o,r.children)),e.append(h),h.prev("."+s)[0]&&h.prev().children(".layui-tree-pack").addClass("layui-tree-showLine"),l||h.parent(".layui-tree-pack").addClass("layui-tree-lineExtend"),n.spread(h,r),t.showCheckbox&&(r.checked&&n.checkids.push(r.id),n.checkClick(h,r)),t.edit&&n.operate(h,r)})},b.prototype.spread=function(e,a){var n=this,t=n.config,r=e.children("."+p),l=r.children("."+f),c=r.find("."+o),k=r.find("."+y),m=t.onlyIconControl?c:l,x="";m.on("click",function(i){var a=e.children("."+v),n=m.children(".layui-icon")[0]?m.children(".layui-icon"):m.find(".layui-tree-icon").children(".layui-icon");if(a[0]){if(e.hasClass(C))e.removeClass(C),a.slideUp(200),n.removeClass(u).addClass(h);else if(e.addClass(C),a.slideDown(200),n.addClass(u).removeClass(h),t.accordion){var r=e.siblings("."+s);r.removeClass(C),r.children("."+v).slideUp(200),r.find(".layui-tree-icon").children(".layui-icon").removeClass(u).addClass(h)}}else x="normal"}),k.on("click",function(){var n=i(this);n.hasClass(d)||(x=e.hasClass(C)?t.onlyIconControl?"open":"close":t.onlyIconControl?"close":"open",t.click&&t.click({elem:e,state:x,data:a}))})},b.prototype.setCheckbox=function(e,i,a){var n=this,t=(n.config,a.prop("checked"));if(!a.prop("disabled")){if("object"==typeof i.children||e.find("."+v)[0]){var r=e.find("."+v).find('input[same="layuiTreeCheck"]');r.each(function(){this.disabled||(this.checked=t)})}var l=function(e){if(e.parents("."+s)[0]){var i,a=e.parent("."+v),n=a.parent(),r=a.prev().find('input[same="layuiTreeCheck"]');t?r.prop("checked",t):(a.find('input[same="layuiTreeCheck"]').each(function(){this.checked&&(i=!0)}),i||r.prop("checked",!1)),l(n)}};l(e),n.renderForm("checkbox")}},b.prototype.checkClick=function(e,a){var n=this,t=n.config,r=e.children("."+p),l=r.children("."+f);l.on("click",'input[same="layuiTreeCheck"]+',function(r){layui.stope(r);var l=i(this).prev(),c=l.prop("checked");l.prop("disabled")||(n.setCheckbox(e,a,l),t.oncheck&&t.oncheck({elem:e,checked:c,data:a}))})},b.prototype.operate=function(e,a){var t=this,r=t.config,l=e.children("."+p),d=l.children("."+f);l.children(".layui-tree-btnGroup").on("click",".layui-icon",function(l){layui.stope(l);var f=i(this).data("type"),b=e.children("."+v),g={data:a,type:f,elem:e};if("add"==f){b[0]||(r.showLine?(d.find("."+o).addClass("layui-tree-icon"),d.find("."+o).children(".layui-icon").addClass(h).removeClass("layui-icon-file")):d.find(".layui-tree-iconArrow").removeClass(c),e.append('
                '));var w=r.operate&&r.operate(g),N={};if(N.title=r.text.defaultNodeName,N.id=w,t.tree(e.children("."+v),[N]),r.showLine)if(b[0])b.hasClass(x)||b.addClass(x),e.find("."+v).each(function(){i(this).children("."+s).last().addClass(k)}),b.children("."+s).last().prev().hasClass(k)?b.children("."+s).last().prev().removeClass(k):b.children("."+s).last().removeClass(k),!e.parent("."+v)[0]&&e.next()[0]&&b.children("."+s).last().removeClass(k);else{var T=e.siblings("."+s),L=1,A=e.parent("."+v);layui.each(T,function(e,a){i(a).children("."+v)[0]||(L=0)}),1==L?(T.children("."+v).addClass(m),T.children("."+v).children("."+s).removeClass(k),e.children("."+v).addClass(m),A.removeClass(x),A.children("."+s).last().children("."+v).children("."+s).last().addClass(k)):e.children("."+v).children("."+s).addClass(k)}if(!r.showCheckbox)return;if(d.find('input[same="layuiTreeCheck"]')[0].checked){var I=e.children("."+v).children("."+s).last();I.find('input[same="layuiTreeCheck"]')[0].checked=!0}t.renderForm("checkbox")}else if("update"==f){var F=d.children("."+y).html();d.children("."+y).html(""),d.append(''),d.children(".layui-tree-editInput").val(F).focus();var j=function(e){var i=e.val().trim();i=i?i:r.text.defaultNodeName,e.remove(),d.children("."+y).html(i),g.data.title=i,r.operate&&r.operate(g)};d.children(".layui-tree-editInput").blur(function(){j(i(this))}),d.children(".layui-tree-editInput").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),j(i(this)))})}else n.confirm('确认删除该节点 "'+(a.title||"")+'" 吗?',function(a){if(r.operate&&r.operate(g),g.status="remove",n.close(a),!e.prev("."+s)[0]&&!e.next("."+s)[0]&&!e.parent("."+v)[0])return e.remove(),void t.elem.append(t.elemNone);if(e.siblings("."+s).children("."+p)[0]){if(r.showCheckbox){var l=function(e){if(e.parents("."+s)[0]){var a=e.siblings("."+s).children("."+p),n=e.parent("."+v).prev(),r=n.find('input[same="layuiTreeCheck"]')[0],c=1,d=0;0==r.checked&&(a.each(function(e,a){var n=i(a).find('input[same="layuiTreeCheck"]')[0];0!=n.checked||n.disabled||(c=0),n.disabled||(d=1)}),1==c&&1==d&&(r.checked=!0,t.renderForm("checkbox"),l(n.parent("."+s))))}};l(e)}if(r.showLine){var d=e.siblings("."+s),h=1,f=e.parent("."+v);layui.each(d,function(e,a){i(a).children("."+v)[0]||(h=0)}),1==h?(b[0]||(f.removeClass(x),d.children("."+v).addClass(m),d.children("."+v).children("."+s).removeClass(k)),e.next()[0]?f.children("."+s).last().children("."+v).children("."+s).last().addClass(k):e.prev().children("."+v).children("."+s).last().addClass(k),e.next()[0]||e.parents("."+s)[1]||e.parents("."+s).eq(0).next()[0]||e.prev("."+s).addClass(k)):!e.next()[0]&&e.hasClass(k)&&e.prev().addClass(k)}}else{var y=e.parent("."+v).prev();if(r.showLine){y.find("."+o).removeClass("layui-tree-icon"),y.find("."+o).children(".layui-icon").removeClass(u).addClass("layui-icon-file");var w=y.parents("."+v).eq(0);w.addClass(x),w.children("."+s).each(function(){i(this).children("."+v).children("."+s).last().addClass(k)})}else y.find(".layui-tree-iconArrow").addClass(c);e.parents("."+s).eq(0).removeClass(C),e.parent("."+v).remove()}e.remove()})})},b.prototype.events=function(){var e=this,a=e.config;e.elem.find(".layui-tree-checkedFirst");e.setChecked(e.checkids),e.elem.find(".layui-tree-search").on("keyup",function(){var n=i(this),t=n.val(),r=n.nextAll(),l=[];r.find("."+y).each(function(){var e=i(this).parents("."+p);if(i(this).html().indexOf(t)!=-1){l.push(i(this).parent());var a=function(e){e.addClass("layui-tree-searchShow"),e.parent("."+v)[0]&&a(e.parent("."+v).parent("."+s))};a(e.parent("."+s))}}),r.find("."+p).each(function(){var e=i(this).parent("."+s);e.hasClass("layui-tree-searchShow")||e.addClass(c)}),0==r.find(".layui-tree-searchShow").length&&e.elem.append(e.elemNone),a.onsearch&&a.onsearch({elem:l})}),e.elem.find(".layui-tree-search").on("keydown",function(){i(this).nextAll().find("."+p).each(function(){var e=i(this).parent("."+s);e.removeClass("layui-tree-searchShow "+c)}),i(".layui-tree-emptyText")[0]&&i(".layui-tree-emptyText").remove()})},b.prototype.getChecked=function(){var e=this,a=e.config,n=[],t=[];e.elem.find(".layui-form-checked").each(function(){n.push(i(this).prev()[0].value)});var r=function(e,a){layui.each(e,function(e,t){layui.each(n,function(e,n){if(t.id==n){var l=i.extend({},t);return delete l.children,a.push(l),t.children&&(l.children=[],r(t.children,l.children)),!0}})})};return r(i.extend({},a.data),t),t},b.prototype.setChecked=function(e){var a=this;a.config;a.elem.find("."+s).each(function(a,n){var t=i(this).data("id"),r=i(n).children("."+p).find('input[same="layuiTreeCheck"]'),l=r.next();if("number"==typeof e){if(t==e)return r[0].checked||l.click(),!1}else"object"==typeof e&&layui.each(e,function(e,i){if(i==t&&!r[0].checked)return l.click(),!0})})},l.that={},l.config={},r.reload=function(e,i){var a=l.that[e];return a.reload(i),l.call(a)},r.getChecked=function(e){var i=l.that[e];return i.getChecked()},r.setChecked=function(e,i){var a=l.that[e];return a.setChecked(i)},r.render=function(e){var i=new b(e);return l.call(i)},e(t,r)});layui.define(["laytpl","form"],function(e){"use strict";var a=layui.$,t=layui.laytpl,i=layui.form,n="transfer",l={config:{},index:layui[n]?layui[n].index+1e4:0,set:function(e){var t=this;return t.config=a.extend({},t.config,e),t},on:function(e,a){return layui.onevent.call(this,n,e,a)}},r=function(){var e=this,a=e.config,t=a.id||e.index;return r.that[t]=e,r.config[t]=a,{config:a,reload:function(a){e.reload.call(e,a)},getData:function(){return e.getData.call(e)}}},c="layui-hide",o="layui-btn-disabled",d="layui-none",s="layui-transfer-box",u="layui-transfer-header",h="layui-transfer-search",f="layui-transfer-active",y="layui-transfer-data",p=function(e){return e=e||{},['
                ','
                ','","
                ","{{# if(d.data.showSearch){ }}",'","{{# } }}",'
                  ',"
                  "].join("")},v=['
                  ',p({index:0,checkAllName:"layTransferLeftCheckAll"}),'
                  ','",'","
                  ",p({index:1,checkAllName:"layTransferRightCheckAll"}),"
                  "].join(""),x=function(e){var t=this;t.index=++l.index,t.config=a.extend({},t.config,l.config,e),t.render()};x.prototype.config={title:["列表一","列表二"],width:200,height:360,data:[],value:[],showSearch:!1,id:"",text:{none:"无数据",searchNone:"无匹配数据"}},x.prototype.reload=function(e){var t=this;t.config=a.extend({},t.config,e),t.render()},x.prototype.render=function(){var e=this,i=e.config,n=e.elem=a(t(v).render({data:i,index:e.index})),l=i.elem=a(i.elem);l[0]&&(i.data=i.data||[],i.value=i.value||[],e.key=i.id||e.index,l.html(e.elem),e.layBox=e.elem.find("."+s),e.layHeader=e.elem.find("."+u),e.laySearch=e.elem.find("."+h),e.layData=n.find("."+y),e.layBtn=n.find("."+f+" .layui-btn"),e.layBox.css({width:i.width,height:i.height}),e.layData.css({height:function(){return i.height-e.layHeader.outerHeight()-e.laySearch.outerHeight()-2}()}),e.renderData(),e.events())},x.prototype.renderData=function(){var e=this,a=(e.config,[{checkName:"layTransferLeftCheck",views:[]},{checkName:"layTransferRightCheck",views:[]}]);e.parseData(function(e){var t=e.selected?1:0,i=["
                • ",'',"
                • "].join("");a[t].views.push(i),delete e.selected}),e.layData.eq(0).html(a[0].views.join("")),e.layData.eq(1).html(a[1].views.join("")),e.renderCheckBtn()},x.prototype.renderForm=function(e){i.render(e,"LAY-transfer-"+this.index)},x.prototype.renderCheckBtn=function(e){var t=this,i=t.config;e=e||{},t.layBox.each(function(n){var l=a(this),r=l.find("."+y),d=l.find("."+u).find('input[type="checkbox"]'),s=r.find('input[type="checkbox"]'),h=0,f=!1;if(s.each(function(){var e=a(this).data("hide");(this.checked||this.disabled||e)&&h++,this.checked&&!e&&(f=!0)}),d.prop("checked",f&&h===s.length),t.layBtn.eq(n)[f?"removeClass":"addClass"](o),!e.stopNone){var p=r.children("li:not(."+c+")").length;t.noneView(r,p?"":i.text.none)}}),t.renderForm("checkbox")},x.prototype.noneView=function(e,t){var i=a('

                  '+(t||"")+"

                  ");e.find("."+d)[0]&&e.find("."+d).remove(),t.replace(/\s/g,"")&&e.append(i)},x.prototype.setValue=function(){var e=this,t=e.config,i=[];return e.layBox.eq(1).find("."+y+' input[type="checkbox"]').each(function(){var e=a(this).data("hide");e||i.push(this.value)}),t.value=i,e},x.prototype.parseData=function(e){var t=this,i=t.config,n=[];return layui.each(i.data,function(t,l){l=("function"==typeof i.parseData?i.parseData(l):l)||l,n.push(l=a.extend({},l)),layui.each(i.value,function(e,a){a==l.value&&(l.selected=!0)}),e&&e(l)}),i.data=n,t},x.prototype.getData=function(e){var a=this,t=a.config,i=[];return a.setValue(),layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&i.push(t)})}),i},x.prototype.events=function(){var e=this,t=e.config;e.elem.on("click",'input[lay-filter="layTransferCheckbox"]+',function(){var t=a(this).prev(),i=t[0].checked,n=t.parents("."+s).eq(0).find("."+y);t[0].disabled||("all"===t.attr("lay-type")&&n.find('input[type="checkbox"]').each(function(){this.disabled||(this.checked=i)}),e.renderCheckBtn({stopNone:!0}))}),e.layBtn.on("click",function(){var i=a(this),n=i.data("index"),l=e.layBox.eq(n),r=[];if(!i.hasClass(o)){e.layBox.eq(n).each(function(t){var i=a(this),n=i.find("."+y);n.children("li").each(function(){var t=a(this),i=t.find('input[type="checkbox"]'),n=i.data("hide");i[0].checked&&!n&&(i[0].checked=!1,l.siblings("."+s).find("."+y).append(t.clone()),t.remove(),r.push(i[0].value)),e.setValue()})}),e.renderCheckBtn();var c=l.siblings("."+s).find("."+h+" input");""===c.val()||c.trigger("keyup"),t.onchange&&t.onchange(e.getData(r),n)}}),e.laySearch.find("input").on("keyup",function(){var i=this.value,n=a(this).parents("."+h).eq(0).siblings("."+y),l=n.children("li");l.each(function(){var e=a(this),t=e.find('input[type="checkbox"]'),n=t[0].title.indexOf(i)!==-1;e[n?"removeClass":"addClass"](c),t.data("hide",!n)}),e.renderCheckBtn();var r=l.length===n.children("li."+c).length;e.noneView(n,r?t.text.searchNone:"")})},r.that={},r.config={},l.reload=function(e,a){var t=r.that[e];return t.reload(a),r.call(t)},l.getData=function(e){var a=r.that[e];return a.getData()},l.render=function(e){var a=new x(e);return r.call(a)},e(n,l)});layui.define(["laytpl","laypage","layer","form","util"],function(e){"use strict";var t=layui.$,i=layui.laytpl,a=layui.laypage,l=layui.layer,n=layui.form,o=(layui.util,layui.hint()),r=layui.device(),d={config:{checkName:"LAY_CHECKED",indexName:"LAY_TABLE_INDEX"},cache:{},index:layui.table?layui.table.index+1e4:0,set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,y,e,t)}},c=function(){var e=this,t=e.config,i=t.id||t.index;return i&&(c.that[i]=e,c.config[i]=t),{config:t,reload:function(t,i){e.reload.call(e,t,i)},setColsWidth:function(){e.setColsWidth.call(e)},resize:function(){e.resize.call(e)}}},s=function(e){var t=c.config[e];return t||o.error(e?"The table instance with ID '"+e+"' not found":"ID argument required"),t||null},u=function(e,a,l,n){var o=e.templet?function(){return"function"==typeof e.templet?e.templet(l):i(t(e.templet).html()||String(a)).render(l)}():a;return n?t("
                  "+o+"
                  ").text():o},y="table",h=".layui-table",f="layui-hide",p="layui-none",v="layui-table-view",m=".layui-table-tool",g=".layui-table-box",b=".layui-table-init",x=".layui-table-header",k=".layui-table-body",C=".layui-table-main",w=".layui-table-fixed",T=".layui-table-fixed-l",N=".layui-table-fixed-r",A=".layui-table-total",L=".layui-table-page",S=".layui-table-sort",R="layui-table-edit",W="layui-table-hover",_=function(e){var t='{{#if(item2.colspan){}} colspan="{{item2.colspan}}"{{#} if(item2.rowspan){}} rowspan="{{item2.rowspan}}"{{#}}}';return e=e||{},['',"","{{# layui.each(d.data.cols, function(i1, item1){ }}","","{{# layui.each(item1, function(i2, item2){ }}",'{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}','{{# if(item2.fixed === "right"){ right = true; } }}',function(){return e.fixed&&"right"!==e.fixed?'{{# if(item2.fixed && item2.fixed !== "right"){ }}':"right"===e.fixed?'{{# if(item2.fixed === "right"){ }}':""}(),"{{# var isSort = !(item2.colGroup) && item2.sort; }}",'",e.fixed?"{{# }; }}":"","{{# }); }}","","{{# }); }}","","
                  ','
                  ','{{# if(item2.type === "checkbox"){ }}','',"{{# } else { }}",'{{item2.title||""}}',"{{# if(isSort){ }}",'',"{{# } }}","{{# } }}","
                  ","
                  "].join("")},z=['',"","
                  "].join(""),E=['
                  ',"{{# if(d.data.toolbar){ }}",'
                  ','
                  ','
                  ',"
                  ","{{# } }}",'
                  ',"{{# if(d.data.loading){ }}",'
                  ','',"
                  ","{{# } }}","{{# var left, right; }}",'
                  ',_(),"
                  ",'
                  ',z,"
                  ","{{# if(left){ }}",'
                  ','
                  ',_({fixed:!0}),"
                  ",'
                  ',z,"
                  ","
                  ","{{# }; }}","{{# if(right){ }}",'
                  ','
                  ',_({fixed:"right"}),'
                  ',"
                  ",'
                  ',z,"
                  ","
                  ","{{# }; }}","
                  ","{{# if(d.data.totalRow){ }}",'
                  ','','',"
                  ","
                  ","{{# } }}","{{# if(d.data.page){ }}",'
                  ','
                  ',"
                  ","{{# } }}","","
                  "].join(""),j=t(window),F=t(document),I=function(e){var i=this;i.index=++d.index,i.config=t.extend({},i.config,d.config,e),i.render()};I.prototype.config={limit:10,loading:!0,cellMinWidth:60,defaultToolbar:["filter","exports","print"],autoSort:!0,text:{none:"无数据"}},I.prototype.render=function(){var e=this,a=e.config;if(a.elem=t(a.elem),a.where=a.where||{},a.id=a.id||a.elem.attr("id")||e.index,a.request=t.extend({pageName:"page",limitName:"limit"},a.request),a.response=t.extend({statusName:"code",statusCode:0,msgName:"msg",dataName:"data",totalRowName:"totalRow",countName:"count"},a.response),"object"==typeof a.page&&(a.limit=a.page.limit||a.limit,a.limits=a.page.limits||a.limits,e.page=a.page.curr=a.page.curr||1,delete a.page.elem,delete a.page.jump),!a.elem[0])return e;a.height&&/^full-\d+$/.test(a.height)&&(e.fullHeightGap=a.height.split("-")[1],a.height=j.height()-e.fullHeightGap),e.setInit();var l=a.elem,n=l.next("."+v),o=e.elem=t(i(E).render({VIEW_CLASS:v,data:a,index:e.index}));if(a.index=e.index,e.key=a.id||a.index,n[0]&&n.remove(),l.after(o),e.layTool=o.find(m),e.layBox=o.find(g),e.layHeader=o.find(x),e.layMain=o.find(C),e.layBody=o.find(k),e.layFixed=o.find(w),e.layFixLeft=o.find(T),e.layFixRight=o.find(N),e.layTotal=o.find(A),e.layPage=o.find(L),e.renderToolbar(),e.fullSize(),a.cols.length>1){var r=e.layFixed.find(x).find("th");r.height(e.layHeader.height()-1-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom")))}e.pullData(e.page),e.events()},I.prototype.initOpts=function(e){var t=this,i=(t.config,{checkbox:48,radio:48,space:15,numbers:40});e.checkbox&&(e.type="checkbox"),e.space&&(e.type="space"),e.type||(e.type="normal"),"normal"!==e.type&&(e.unresize=!0,e.width=e.width||i[e.type])},I.prototype.setInit=function(e){var t=this,i=t.config;return i.clientWidth=i.width||function(){var e=function(t){var a,l;t=t||i.elem.parent(),a=t.width();try{l="none"===t.css("display")}catch(n){}return!t[0]||a&&!l?a:e(t.parent())};return e()}(),"width"===e?i.clientWidth:void layui.each(i.cols,function(e,a){layui.each(a,function(l,n){if(!n)return void a.splice(l,1);if(n.key=e+"-"+l,n.hide=n.hide||!1,n.colGroup||n.colspan>1){var o=0;layui.each(i.cols[e+1],function(t,i){i.HAS_PARENT||o>1&&o==n.colspan||(i.HAS_PARENT=!0,i.parentKey=e+"-"+l,o+=parseInt(i.colspan>1?i.colspan:1))}),n.colGroup=!0}t.initOpts(n)})})},I.prototype.renderToolbar=function(){var e=this,a=e.config,l=['
                  ','
                  ','
                  '].join(""),n=e.layTool.find(".layui-table-tool-temp");if("default"===a.toolbar)n.html(l);else if("string"==typeof a.toolbar){var o=t(a.toolbar).html()||"";o&&n.html(i(o).render(a))}var r={filter:{title:"筛选列",layEvent:"LAYTABLE_COLS",icon:"layui-icon-cols"},exports:{title:"导出",layEvent:"LAYTABLE_EXPORT",icon:"layui-icon-export"},print:{title:"打印",layEvent:"LAYTABLE_PRINT",icon:"layui-icon-print"}},d=[];"object"==typeof a.defaultToolbar&&layui.each(a.defaultToolbar,function(e,t){var i="string"==typeof t?r[t]:t;i&&d.push('
                  ')}),e.layTool.find(".layui-table-tool-self").html(d.join(""))},I.prototype.setParentCol=function(e,t){var i=this,a=i.config,l=i.layHeader.find('th[data-key="'+a.index+"-"+t+'"]'),n=parseInt(l.attr("colspan"))||0;if(l[0]){var o=t.split("-"),r=a.cols[o[0]][o[1]];e?n--:n++,l.attr("colspan",n),l[n<1?"addClass":"removeClass"](f),r.colspan=n,r.hide=n<1;var d=l.data("parentkey");d&&i.setParentCol(e,d)}},I.prototype.setColsPatch=function(){var e=this,t=e.config;layui.each(t.cols,function(t,i){layui.each(i,function(t,i){i.hide&&e.setParentCol(i.hide,i.parentKey)})})},I.prototype.setColsWidth=function(){var e=this,t=e.config,i=0,a=0,l=0,n=0,o=e.setInit("width");e.eachCols(function(e,t){t.hide||i++}),o=o-function(){return"line"===t.skin||"nob"===t.skin?2:i+1}()-e.getScrollWidth(e.layMain[0])-1;var r=function(e){layui.each(t.cols,function(i,r){layui.each(r,function(i,d){var c=0,s=d.minWidth||t.cellMinWidth;return d?void(d.colGroup||d.hide||(e?l&&ln&&a&&(l=(o-n)/a)};r(),r(!0),e.autoColNums=a,e.eachCols(function(i,a){var n=a.minWidth||t.cellMinWidth;a.colGroup||a.hide||(0===a.width?e.getCssRule(t.index+"-"+a.key,function(e){e.style.width=Math.floor(l>=n?l:n)+"px"}):/\d+%$/.test(a.width)&&e.getCssRule(t.index+"-"+a.key,function(e){e.style.width=Math.floor(parseFloat(a.width)/100*o)+"px"}))});var d=e.layMain.width()-e.getScrollWidth(e.layMain[0])-e.layMain.children("table").outerWidth();if(e.autoColNums&&d>=-i&&d<=i){var c=function(t){var i;return t=t||e.layHeader.eq(0).find("thead th:last-child"),i=t.data("field"),!i&&t.prev()[0]?c(t.prev()):t},s=c(),u=s.data("key");e.getCssRule(u,function(t){var i=t.style.width||s.outerWidth();t.style.width=parseFloat(i)+d+"px",e.layMain.height()-e.layMain.prop("clientHeight")>0&&(t.style.width=parseFloat(t.style.width)-1+"px")})}e.loading(!0)},I.prototype.resize=function(){var e=this;e.fullSize(),e.setColsWidth(),e.scrollPatch()},I.prototype.reload=function(e,i){var a=this;e=e||{},delete a.haveInit,e.data&&e.data.constructor===Array&&delete a.config.data,a.config=t.extend(i,{},a.config,e),a.render()},I.prototype.errorView=function(e){var i=this,a=i.layMain.find("."+p),l=t('
                  '+(e||"Error")+"
                  ");a[0]&&(i.layNone.remove(),a.remove()),i.layFixed.addClass(f),i.layMain.find("tbody").html(""),i.layMain.append(i.layNone=l),d.cache[i.key]=[]},I.prototype.page=1,I.prototype.pullData=function(e){var i=this,a=i.config,l=a.request,n=a.response,o=function(){"object"==typeof a.initSort&&i.sort(a.initSort.field,a.initSort.type)};if(i.startTime=(new Date).getTime(),a.url){var r={};r[l.pageName]=e,r[l.limitName]=a.limit;var d=t.extend(r,a.where);a.contentType&&0==a.contentType.indexOf("application/json")&&(d=JSON.stringify(d)),i.loading(),t.ajax({type:a.method||"get",url:a.url,contentType:a.contentType,data:d,dataType:"json",headers:a.headers||{},success:function(t){"function"==typeof a.parseData&&(t=a.parseData(t)||t),t[n.statusName]!=n.statusCode?(i.renderForm(),i.errorView(t[n.msgName]||'返回的数据不符合规范,正确的成功状态码应为:"'+n.statusName+'": '+n.statusCode)):(i.renderData(t,e,t[n.countName]),o(),a.time=(new Date).getTime()-i.startTime+" ms"),i.setColsWidth(),"function"==typeof a.done&&a.done(t,e,t[n.countName])},error:function(e,t){i.errorView("数据接口请求异常:"+t),i.renderForm(),i.setColsWidth(),"function"==typeof a.error&&a.error(e,t)}})}else if(a.data&&a.data.constructor===Array){var c={},s=e*a.limit-a.limit;c[n.dataName]=a.data.concat().splice(s,a.limit),c[n.countName]=a.data.length,"object"==typeof a.totalRow&&(c[n.totalRowName]=t.extend({},a.totalRow)),i.renderData(c,e,c[n.countName]),o(),i.setColsWidth(),"function"==typeof a.done&&a.done(c,e,c[n.countName])}},I.prototype.eachCols=function(e){var t=this;return d.eachCols(null,e,t.config.cols),t},I.prototype.renderData=function(e,n,o,r){var c=this,s=c.config,y=e[s.response.dataName]||[],h=e[s.response.totalRowName],v=[],m=[],g=[],b=function(){var e;return!r&&c.sortKey?c.sort(c.sortKey.field,c.sortKey.sort,!0):(layui.each(y,function(a,l){var o=[],y=[],h=[],p=a+s.limit*(n-1)+1;0!==l.length&&(r||(l[d.config.indexName]=a),c.eachCols(function(n,r){var c=r.field||n,v=s.index+"-"+r.key,m=l[c];if(void 0!==m&&null!==m||(m=""),!r.colGroup){var g=['','
                  '+function(){var n=t.extend(!0,{LAY_INDEX:p},l),o=d.config.checkName;switch(r.type){case"checkbox":return'";case"radio":return n[o]&&(e=a),'';case"numbers":return p}return r.toolbar?i(t(r.toolbar).html()||"").render(n):u(r,m,n)}(),"
                  "].join("");o.push(g),r.fixed&&"right"!==r.fixed&&y.push(g),"right"===r.fixed&&h.push(g)}}),v.push(''+o.join("")+""),m.push(''+y.join("")+""),g.push(''+h.join("")+""))}),c.layBody.scrollTop(0),c.layMain.find("."+p).remove(),c.layMain.find("tbody").html(v.join("")),c.layFixLeft.find("tbody").html(m.join("")),c.layFixRight.find("tbody").html(g.join("")),c.renderForm(),"number"==typeof e&&c.setThisRowChecked(e),c.syncCheckAll(),c.haveInit?c.scrollPatch():setTimeout(function(){c.scrollPatch()},50),c.haveInit=!0,l.close(c.tipsIndex),s.HAS_SET_COLS_PATCH||c.setColsPatch(),void(s.HAS_SET_COLS_PATCH=!0))};return d.cache[c.key]=y,c.layPage[0==o||0===y.length&&1==n?"addClass":"removeClass"](f),0===y.length?(c.renderForm(),c.errorView(s.text.none)):(c.layFixed.removeClass(f),r?b():(b(),c.renderTotal(y,h),void(s.page&&(s.page=t.extend({elem:"layui-table-page"+s.index,count:o,limit:s.limit,limits:s.limits||[10,20,30,40,50,60,70,80,90],groups:3,layout:["prev","page","next","skip","count","limit"],prev:'',next:'',jump:function(e,t){t||(c.page=e.curr,s.limit=e.limit,c.pullData(e.curr))}},s.page),s.page.count=o,a.render(s.page)))))},I.prototype.renderTotal=function(e,a){var l=this,n=l.config,o={};if(n.totalRow){layui.each(e,function(e,t){0!==t.length&&l.eachCols(function(e,i){var a=i.field||e,l=t[a];i.totalRow&&(o[a]=(o[a]||0)+(parseFloat(l)||0))})}),l.dataTotal={};var r=[];l.eachCols(function(e,d){var c=d.field||e,s=function(){var e=d.totalRowText||"",t=parseFloat(o[c]).toFixed(2),i={};return i[c]=t,t=u(d,t,i),a?a[d.field]||e:d.totalRow?t||e:e}(),y=['','
                  '+function(){var e=d.totalRow||n.totalRow;return"string"==typeof e?i(e).render(t.extend({TOTAL_NUMS:s},d)):s}(),"
                  "].join("");d.field&&(l.dataTotal[c]=s),r.push(y)}),l.layTotal.find("tbody").html(""+r.join("")+"")}},I.prototype.getColElem=function(e,t){var i=this,a=i.config;return e.eq(0).find(".laytable-cell-"+(a.index+"-"+t)+":eq(0)")},I.prototype.renderForm=function(e){n.render(e,"LAY-table-"+this.index)},I.prototype.setThisRowChecked=function(e){var t=this,i=(t.config,"layui-table-click"),a=t.layBody.find('tr[data-index="'+e+'"]');a.addClass(i).siblings("tr").removeClass(i)},I.prototype.sort=function(e,i,a,l){var n,r,c=this,s={},u=c.config,h=u.elem.attr("lay-filter"),f=d.cache[c.key];"string"==typeof e&&(n=e,c.layHeader.find("th").each(function(i,a){var l=t(this),o=l.data("field");if(o===e)return e=l,n=o,!1}));try{var n=n||e.data("field"),p=e.data("key");if(c.sortKey&&!a&&n===c.sortKey.field&&i===c.sortKey.sort)return;var v=c.layHeader.find("th .laytable-cell-"+p).find(S);c.layHeader.find("th").find(S).removeAttr("lay-sort"),v.attr("lay-sort",i||null),c.layFixed.find("th")}catch(m){o.error("Table modules: sort field '"+n+"' not matched")}c.sortKey={field:n,sort:i},u.autoSort&&("asc"===i?r=layui.sort(f,n):"desc"===i?r=layui.sort(f,n,!0):(r=layui.sort(f,d.config.indexName),delete c.sortKey)),s[u.response.dataName]=r||f,c.renderData(s,c.page,c.count,!0),l&&layui.event.call(e,y,"sort("+h+")",{field:n,type:i})},I.prototype.loading=function(e){var i=this,a=i.config;a.loading&&(e?(i.layInit&&i.layInit.remove(),delete i.layInit,i.layBox.find(b).remove()):(i.layInit=t(['
                  ','',"
                  "].join("")),i.layBox.append(i.layInit)))},I.prototype.setCheckData=function(e,t){var i=this,a=i.config,l=d.cache[i.key];l[e]&&l[e].constructor!==Array&&(l[e][a.checkName]=t)},I.prototype.syncCheckAll=function(){var e=this,t=e.config,i=e.layHeader.find('input[name="layTableCheckbox"]'),a=function(i){return e.eachCols(function(e,a){"checkbox"===a.type&&(a[t.checkName]=i)}),i};i[0]&&(d.checkStatus(e.key).isAll?(i[0].checked||(i.prop("checked",!0),e.renderForm("checkbox")),a(!0)):(i[0].checked&&(i.prop("checked",!1),e.renderForm("checkbox")),a(!1)))},I.prototype.getCssRule=function(e,t){var i=this,a=i.elem.find("style")[0],l=a.sheet||a.styleSheet||{},n=l.cssRules||l.rules;layui.each(n,function(i,a){if(a.selectorText===".laytable-cell-"+e)return t(a),!0})},I.prototype.fullSize=function(){var e,t=this,i=t.config,a=i.height;t.fullHeightGap&&(a=j.height()-t.fullHeightGap,a<135&&(a=135),t.elem.css("height",a)),a&&(e=parseFloat(a)-(t.layHeader.outerHeight()||38),i.toolbar&&(e-=t.layTool.outerHeight()||50),i.totalRow&&(e-=t.layTotal.outerHeight()||40),i.page&&(e-=t.layPage.outerHeight()||41),t.layMain.css("height",e-2))},I.prototype.getScrollWidth=function(e){var t=0;return e?t=e.offsetWidth-e.clientWidth:(e=document.createElement("div"),e.style.width="100px",e.style.height="100px",e.style.overflowY="scroll",document.body.appendChild(e),t=e.offsetWidth-e.clientWidth,document.body.removeChild(e)),t},I.prototype.scrollPatch=function(){var e=this,i=e.layMain.children("table"),a=e.layMain.width()-e.layMain.prop("clientWidth"),l=e.layMain.height()-e.layMain.prop("clientHeight"),n=(e.getScrollWidth(e.layMain[0]),i.outerWidth()-e.layMain.width()),o=function(e){if(a&&l){if(e=e.eq(0),!e.find(".layui-table-patch")[0]){var i=t('
                  ');i.find("div").css({width:a}),e.find("tr").append(i)}}else e.find(".layui-table-patch").remove()};o(e.layHeader),o(e.layTotal);var r=e.layMain.height(),d=r-l;e.layFixed.find(k).css("height",i.height()>=d?d:"auto"),e.layFixRight[n>0?"removeClass":"addClass"](f),e.layFixRight.css("right",a-1)},I.prototype.events=function(){var e,i=this,a=i.config,o=t("body"),c={},s=i.layHeader.find("th"),h=".layui-table-cell",p=a.elem.attr("lay-filter");i.layTool.on("click","*[lay-event]",function(e){var o=t(this),c=o.attr("lay-event"),s=function(e){var l=t(e.list),n=t('
                    ');n.html(l),a.height&&n.css("max-height",a.height-(i.layTool.outerHeight()||50)),o.find(".layui-table-tool-panel")[0]||o.append(n),i.renderForm(),n.on("click",function(e){layui.stope(e)}),e.done&&e.done(n,l)};switch(layui.stope(e),F.trigger("table.tool.panel.remove"),l.close(i.tipsIndex),c){case"LAYTABLE_COLS":s({list:function(){var e=[];return i.eachCols(function(t,i){i.field&&"normal"==i.type&&e.push('
                  • ')}),e.join("")}(),done:function(){n.on("checkbox(LAY_TABLE_TOOL_COLS)",function(e){var l=t(e.elem),n=this.checked,o=l.data("key"),r=l.data("parentkey");layui.each(a.cols,function(e,t){layui.each(t,function(t,l){if(e+"-"+t===o){var d=l.hide;l.hide=!n,i.elem.find('*[data-key="'+a.index+"-"+o+'"]')[n?"removeClass":"addClass"](f),d!=l.hide&&i.setParentCol(!n,r),i.resize()}})})})}});break;case"LAYTABLE_EXPORT":r.ie?l.tips("导出功能不支持 IE,请用 Chrome 等高级浏览器导出",this,{tips:3}):s({list:function(){return['
                  • 导出到 Csv 文件
                  • ','
                  • 导出到 Excel 文件
                  • '].join("")}(),done:function(e,l){l.on("click",function(){var e=t(this).data("type");d.exportFile.call(i,a.id,null,e)})}});break;case"LAYTABLE_PRINT":var u=window.open("打印窗口","_blank"),h=[""].join(""),v=t(i.layHeader.html());v.append(i.layMain.find("table").html()),v.append(i.layTotal.find("table").html()),v.find("th.layui-table-patch").remove(),v.find(".layui-table-col-special").remove(),u.document.write(h+v.prop("outerHTML")),u.document.close(),u.print(),u.close()}layui.event.call(this,y,"toolbar("+p+")",t.extend({event:c,config:a},{}))}),s.on("mousemove",function(e){var i=t(this),a=i.offset().left,l=e.clientX-a;i.data("unresize")||c.resizeStart||(c.allowResize=i.width()-l<=10,o.css("cursor",c.allowResize?"col-resize":""))}).on("mouseleave",function(){t(this);c.resizeStart||o.css("cursor","")}).on("mousedown",function(e){var l=t(this);if(c.allowResize){var n=l.data("key");e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],i.getCssRule(n,function(e){var t=e.style.width||l.outerWidth();c.rule=e,c.ruleWidth=parseFloat(t),c.minWidth=l.data("minwidth")||a.cellMinWidth})}}),F.on("mousemove",function(t){if(c.resizeStart){if(t.preventDefault(),c.rule){var a=c.ruleWidth+t.clientX-c.offset[0];a');return n[0].value=i.data("content")||l.text(),i.find("."+R)[0]||i.append(n),n.focus(),void layui.stope(e)}}).on("mouseenter","td",function(){b.call(this)}).on("mouseleave","td",function(){b.call(this,"hide")});var g="layui-table-grid-down",b=function(e){var i=t(this),a=i.children(h);if(!i.data("off"))if(e)i.find(".layui-table-grid-down").remove();else if(a.prop("scrollWidth")>a.outerWidth()){if(a.find("."+g)[0])return;i.append('
                    ')}};i.layBody.on("click","."+g,function(e){var n=t(this),o=n.parent(),d=o.children(h);i.tipsIndex=l.tips(['
                    ',d.html(),"
                    ",''].join(""),d[0],{tips:[3,""],time:-1,anim:-1,maxWidth:r.ios||r.android?300:i.elem.width()/2,isOutAnim:!1,skin:"layui-table-tips",success:function(e,t){e.find(".layui-table-tips-c").on("click",function(){l.close(t)})}}),layui.stope(e)}),i.layBody.on("click","*[lay-event]",function(){var e=t(this),a=e.parents("tr").eq(0).data("index");layui.event.call(this,y,"tool("+p+")",v.call(this,{event:e.attr("lay-event")})),i.setThisRowChecked(a)}),i.layMain.on("scroll",function(){var e=t(this),a=e.scrollLeft(),n=e.scrollTop();i.layHeader.scrollLeft(a),i.layTotal.scrollLeft(a),i.layFixed.find(k).scrollTop(n),l.close(i.tipsIndex)}),j.on("resize",function(){i.resize()})},function(){F.on("click",function(){F.trigger("table.remove.tool.panel")}),F.on("table.remove.tool.panel",function(){t(".layui-table-tool-panel").remove()})}(),d.init=function(e,i){i=i||{};var a=this,l=t(e?'table[lay-filter="'+e+'"]':h+"[lay-data]"),n="Table element property lay-data configuration item has a syntax error: ";return l.each(function(){var a=t(this),l=a.attr("lay-data");try{l=new Function("return "+l)()}catch(r){o.error(n+l,"error")}var c=[],s=t.extend({elem:this,cols:[],data:[],skin:a.attr("lay-skin"),size:a.attr("lay-size"),even:"string"==typeof a.attr("lay-even")},d.config,i,l);e&&a.hide(),a.find("thead>tr").each(function(e){s.cols[e]=[],t(this).children().each(function(i){var a=t(this),l=a.attr("lay-data");try{l=new Function("return "+l)()}catch(r){return o.error(n+l)}var d=t.extend({title:a.text(),colspan:a.attr("colspan")||0,rowspan:a.attr("rowspan")||0},l);d.colspan<2&&c.push(d),s.cols[e].push(d)})}),a.find("tbody>tr").each(function(e){var i=t(this),a={};i.children("td").each(function(e,i){var l=t(this),n=l.data("field");if(n)return a[n]=l.html()}),layui.each(c,function(e,t){var l=i.children("td").eq(e);a[t.field]=l.html()}),s.data[e]=a}),d.render(s)}),a},c.that={},c.config={},d.eachCols=function(e,i,a){var l=c.config[e]||{},n=[],o=0;a=t.extend(!0,[],a||l.cols),layui.each(a,function(e,t){layui.each(t,function(t,i){if(i.colGroup){var l=0;o++,i.CHILD_COLS=[],layui.each(a[e+1],function(e,t){t.PARENT_COL_INDEX||l>1&&l==i.colspan||(t.PARENT_COL_INDEX=o,i.CHILD_COLS.push(t),l+=parseInt(t.colspan>1?t.colspan:1))})}i.PARENT_COL_INDEX||n.push(i)})});var r=function(e){layui.each(e||n,function(e,t){return t.CHILD_COLS?r(t.CHILD_COLS):void("function"==typeof i&&i(e,t))})};r()},d.checkStatus=function(e){var t=0,i=0,a=[],l=d.cache[e]||[];return layui.each(l,function(e,l){return l.constructor===Array?void i++:void(l[d.config.checkName]&&(t++,a.push(d.clearCacheKey(l))))}),{data:a,isAll:!!l.length&&t===l.length-i}},d.getData=function(e){var t=[],i=d.cache[e]||[];return layui.each(i,function(e,i){i.constructor!==Array&&t.push(d.clearCacheKey(i))}),t},d.exportFile=function(e,t,i){var a=this;t=t||d.clearCacheKey(d.cache[e]),i=i||"csv";var l=c.config[e]||{},n={csv:"text/csv",xls:"application/vnd.ms-excel"}[i],s=document.createElement("a");return r.ie?o.error("IE_NOT_SUPPORT_EXPORTS"):(s.href="data:"+n+";charset=utf-8,\ufeff"+encodeURIComponent(function(){var i=[],l=[],n=[];return layui.each(t,function(t,a){var n=[];"object"==typeof e?(layui.each(e,function(e,a){0==t&&i.push(a||"")}),layui.each(d.clearCacheKey(a),function(e,t){n.push('"'+(t||"")+'"')})):d.eachCols(e,function(e,l){if(l.field&&"normal"==l.type&&!l.hide){var o=a[l.field];void 0!==o&&null!==o||(o=""),0==t&&i.push(l.title||""),n.push('"'+u(l,o,a,"text")+'"')}}),l.push(n.join(","))}),layui.each(a.dataTotal,function(e,t){n.push(t)}),i.join(",")+"\r\n"+l.join("\r\n")+"\r\n"+n.join(",")}()),s.download=(l.title||"table_"+(l.index||""))+"."+i,document.body.appendChild(s),s.click(),void document.body.removeChild(s))},d.resize=function(e){if(e){var t=s(e);if(!t)return;c.that[e].resize()}else layui.each(c.that,function(){this.resize()})},d.reload=function(e,t,i){var a=s(e);if(a){var l=c.that[e];return l.reload(t,i),c.call(l)}},d.render=function(e){var t=new I(e);return c.call(t)},d.clearCacheKey=function(e){return e=t.extend({},e),delete e[d.config.checkName],delete e[d.config.indexName],e},d.init(),e(y,d)});layui.define("jquery",function(e){"use strict";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t="carousel",a="layui-this",l=">*[carousel-item]>*",o="layui-carousel-left",r="layui-carousel-right",d="layui-carousel-prev",s="layui-carousel-next",u="layui-carousel-arrow",c="layui-carousel-ind",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(a),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(clearInterval(e.timer),e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i(['",'"].join(""));n.elem.attr("lay-arrow",n.arrow),n.elem.find("."+u)[0]&&n.elem.find("."+u).remove(),n.elem.append(t),t.on("click",function(){var n=i(this),t=n.attr("lay-type");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['
                      ',function(){var i=[];return layui.each(e.elemItem,function(e){i.push("")}),i.join("")}(),"
                    "].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+c)[0]&&n.elem.find("."+c).remove(),n.elem.append(t),"updown"===n.anim&&t.css("margin-top",-(t.height()/2)),t.find("li").on("hover"===n.trigger?"mouseover":n.trigger,function(){var t=i(this),a=t.index();a>n.index?e.slide("add",a-n.index):al.length&&(l.value=l.length),parseInt(l.value)!==l.value&&(l.half||(l.value=Math.ceil(l.value)-l.value<.5?Math.ceil(l.value):Math.floor(l.value)));for(var n='
                      ",s=1;s<=l.length;s++){var r='
                    • ";l.half&&parseInt(l.value)!==l.value&&s==Math.ceil(l.value)?n=n+'
                    • ":n+=r}n+="
                    "+(l.text?''+l.value+"星":"")+"";var c=l.elem,f=c.next("."+t);f[0]&&f.remove(),e.elemTemp=a(n),l.span=e.elemTemp.next("span"),l.setText&&l.setText(l.value),c.html(e.elemTemp),c.addClass("layui-inline"),l.readonly||e.action()},v.prototype.setvalue=function(e){var a=this,l=a.config;l.value=e,a.render()},v.prototype.action=function(){var e=this,l=e.config,i=e.elemTemp,n=i.find("i").width();i.children("li").each(function(e){var t=e+1,v=a(this);v.on("click",function(e){if(l.value=t,l.half){var o=e.pageX-a(this).offset().left;o<=n/2&&(l.value=l.value-.5)}l.text&&i.next("span").text(l.value+"星"),l.choose&&l.choose(l.value),l.setText&&l.setText(l.value)}),v.on("mousemove",function(e){if(i.find("i").each(function(){a(this).addClass(o).removeClass(r)}),i.find("i:lt("+t+")").each(function(){a(this).addClass(u).removeClass(f)}),l.half){var c=e.pageX-a(this).offset().left;c<=n/2&&v.children("i").addClass(s).removeClass(u)}}),v.on("mouseleave",function(){i.find("i").each(function(){a(this).addClass(o).removeClass(r)}),i.find("i:lt("+Math.floor(l.value)+")").each(function(){a(this).addClass(u).removeClass(f)}),l.half&&parseInt(l.value)!==l.value&&i.children("li:eq("+Math.floor(l.value)+")").children("i").addClass(s).removeClass(c)})})},v.prototype.events=function(){var e=this;e.config},l.render=function(e){var a=new v(e);return i.call(a)},e(n,l)});layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t='';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="加载更多",h=l('");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),!i&&f.width()&&(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;su)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)});layui.define(["layer","form"],function(t){"use strict";var e=layui.$,i=layui.layer,a=layui.form,l=(layui.hint(),layui.device()),n="layedit",o="layui-show",r="layui-disabled",c=function(){var t=this;t.index=0,t.config={tool:["strong","italic","underline","del","|","left","center","right","|","link","unlink","face","image"],hideTool:[],height:280}};c.prototype.set=function(t){var i=this;return e.extend(!0,i.config,t),i},c.prototype.on=function(t,e){return layui.onevent(n,t,e)},c.prototype.build=function(t,i){i=i||{};var a=this,n=a.config,r="layui-layedit",c=e("string"==typeof t?"#"+t:t),u="LAY_layedit_"+ ++a.index,d=c.next("."+r),y=e.extend({},n,i),f=function(){var t=[],e={};return layui.each(y.hideTool,function(t,i){e[i]=!0}),layui.each(y.tool,function(i,a){C[a]&&!e[a]&&t.push(C[a])}),t.join("")}(),m=e(['
                    ','
                    '+f+"
                    ",'
                    ','',"
                    ","
                    "].join(""));return l.ie&&l.ie<8?c.removeClass("layui-hide").addClass(o):(d[0]&&d.remove(),s.call(a,m,c[0],y),c.addClass("layui-hide").after(m),a.index)},c.prototype.getContent=function(t){var e=u(t);if(e[0])return d(e[0].document.body.innerHTML)},c.prototype.getText=function(t){var i=u(t);if(i[0])return e(i[0].document.body).text()},c.prototype.setContent=function(t,i,a){var l=u(t);l[0]&&(a?e(l[0].document.body).append(i):e(l[0].document.body).html(i),layedit.sync(t))},c.prototype.sync=function(t){var i=u(t);if(i[0]){var a=e("#"+i[1].attr("textarea"));a.val(d(i[0].document.body.innerHTML))}},c.prototype.getSelection=function(t){var e=u(t);if(e[0]){var i=m(e[0].document);return document.selection?i.text:i.toString()}};var s=function(t,i,a){var l=this,n=t.find("iframe");n.css({height:a.height}).on("load",function(){var o=n.contents(),r=n.prop("contentWindow"),c=o.find("head"),s=e([""].join("")),u=o.find("body");c.append(s),u.attr("contenteditable","true").css({"min-height":a.height}).html(i.value||""),y.apply(l,[r,n,i,a]),g.call(l,r,t,a)})},u=function(t){var i=e("#LAY_layedit_"+t),a=i.prop("contentWindow");return[a,i]},d=function(t){return 8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),t},y=function(t,a,n,o){var r=t.document,c=e(r.body);c.on("keydown",function(t){var e=t.keyCode;if(13===e){var a=m(r),l=p(a),n=l.parentNode;if("pre"===n.tagName.toLowerCase()){if(t.shiftKey)return;return i.msg("请暂时用shift+enter"),!1}r.execCommand("formatBlock",!1,"

                    ")}}),e(n).parents("form").on("submit",function(){var t=c.html();8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),n.value=t}),c.on("paste",function(e){r.execCommand("formatBlock",!1,"

                    "),setTimeout(function(){f.call(t,c),n.value=c.html()},100)})},f=function(t){var i=this;i.document;t.find("*[style]").each(function(){var t=this.style.textAlign;this.removeAttribute("style"),e(this).css({"text-align":t||""})}),t.find("table").addClass("layui-table"),t.find("script,link").remove()},m=function(t){return t.selection?t.selection.createRange():t.getSelection().getRangeAt(0)},p=function(t){return t.endContainer||t.parentElement().childNodes[0]},v=function(t,i,a){var l=this.document,n=document.createElement(t);for(var o in i)n.setAttribute(o,i[o]);if(n.removeAttribute("text"),l.selection){var r=a.text||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.pasteHTML(e(n).prop("outerHTML")),a.select()}else{var r=a.toString()||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.deleteContents(),a.insertNode(n)}},h=function(t,i){var a=this.document,l="layedit-tool-active",n=p(m(a)),o=function(e){return t.find(".layedit-tool-"+e)};i&&i[i.hasClass(l)?"removeClass":"addClass"](l),t.find(">i").removeClass(l),o("unlink").addClass(r),e(n).parents().each(function(){var t=this.tagName.toLowerCase(),e=this.style.textAlign;"b"!==t&&"strong"!==t||o("b").addClass(l),"i"!==t&&"em"!==t||o("i").addClass(l),"u"===t&&o("u").addClass(l),"strike"===t&&o("d").addClass(l),"p"===t&&("center"===e?o("center").addClass(l):"right"===e?o("right").addClass(l):o("left").addClass(l)),"a"===t&&(o("link").addClass(l),o("unlink").removeClass(r))})},g=function(t,a,l){var n=t.document,o=e(n.body),c={link:function(i){var a=p(i),l=e(a).parent();b.call(o,{href:l.attr("href"),target:l.attr("target")},function(e){var a=l[0];"A"===a.tagName?a.href=e.url:v.call(t,"a",{target:e.target,href:e.url,text:e.url},i)})},unlink:function(t){n.execCommand("unlink")},face:function(e){x.call(this,function(i){v.call(t,"img",{src:i.src,alt:i.alt},e)})},image:function(a){var n=this;layui.use("upload",function(o){var r=l.uploadImage||{};o.render({url:r.url,method:r.type,elem:e(n).find("input")[0],done:function(e){0==e.code?(e.data=e.data||{},v.call(t,"img",{src:e.data.src,alt:e.data.title},a)):i.msg(e.msg||"上传失败")}})})},code:function(e){k.call(o,function(i){v.call(t,"pre",{text:i.code,"lay-lang":i.lang},e)})},help:function(){i.open({type:2,title:"帮助",area:["600px","380px"],shadeClose:!0,shade:.1,skin:"layui-layer-msg",content:["","no"]})}},s=a.find(".layui-layedit-tool"),u=function(){var i=e(this),a=i.attr("layedit-event"),l=i.attr("lay-command");if(!i.hasClass(r)){o.focus();var u=m(n);u.commonAncestorContainer;l?(n.execCommand(l),/justifyLeft|justifyCenter|justifyRight/.test(l)&&n.execCommand("formatBlock",!1,"

                    "),setTimeout(function(){o.focus()},10)):c[a]&&c[a].call(this,u),h.call(t,s,i)}},d=/image/;s.find(">i").on("mousedown",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)||u.call(this)}).on("click",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)&&u.call(this)}),o.on("click",function(){h.call(t,s),i.close(x.index)})},b=function(t,e){var l=this,n=i.open({type:1,id:"LAY_layedit_link",area:"350px",shade:.05,shadeClose:!0,moveType:1,title:"超链接",skin:"layui-layer-msg",content:['

                      ','
                    • ','','
                      ','',"
                      ","
                    • ",'
                    • ','','
                      ','",'","
                      ","
                    • ",'
                    • ','','',"
                    • ","
                    "].join(""),success:function(t,n){var o="submit(layedit-link-yes)";a.render("radio"),t.find(".layui-btn-primary").on("click",function(){i.close(n),l.focus()}),a.on(o,function(t){i.close(b.index),e&&e(t.field)})}});b.index=n},x=function(t){var a=function(){var t=["[微笑]","[嘻嘻]","[哈哈]","[可爱]","[可怜]","[挖鼻]","[吃惊]","[害羞]","[挤眼]","[闭嘴]","[鄙视]","[爱你]","[泪]","[偷笑]","[亲亲]","[生病]","[太开心]","[白眼]","[右哼哼]","[左哼哼]","[嘘]","[衰]","[委屈]","[吐]","[哈欠]","[抱抱]","[怒]","[疑问]","[馋嘴]","[拜拜]","[思考]","[汗]","[困]","[睡]","[钱]","[失望]","[酷]","[色]","[哼]","[鼓掌]","[晕]","[悲伤]","[抓狂]","[黑线]","[阴险]","[怒骂]","[互粉]","[心]","[伤心]","[猪头]","[熊猫]","[兔子]","[ok]","[耶]","[good]","[NO]","[赞]","[来]","[弱]","[草泥马]","[神马]","[囧]","[浮云]","[给力]","[围观]","[威武]","[奥特曼]","[礼物]","[钟]","[话筒]","[蜡烛]","[蛋糕]"],e={};return layui.each(t,function(t,i){e[i]=layui.cache.dir+"images/face/"+t+".gif"}),e}();return x.hide=x.hide||function(t){"face"!==e(t.target).attr("layedit-event")&&i.close(x.index)},x.index=i.tips(function(){var t=[];return layui.each(a,function(e,i){t.push('
                  • '+e+'
                  • ')}),'
                      '+t.join("")+"
                    "}(),this,{tips:1,time:0,skin:"layui-box layui-util-face",maxWidth:500,success:function(l,n){l.css({marginTop:-4,marginLeft:-10}).find(".layui-clear>li").on("click",function(){t&&t({src:a[this.title],alt:this.title}),i.close(n)}),e(document).off("click",x.hide).on("click",x.hide)}})},k=function(t){var e=this,l=i.open({type:1,id:"LAY_layedit_code",area:"550px",shade:.05,shadeClose:!0,moveType:1,title:"插入代码",skin:"layui-layer-msg",content:['
                      ','
                    • ','','
                      ','","
                      ","
                    • ",'
                    • ','','
                      ','',"
                      ","
                    • ",'
                    • ','','',"
                    • ","
                    "].join(""),success:function(l,n){var o="submit(layedit-code-yes)";a.render("select"),l.find(".layui-btn-primary").on("click",function(){i.close(n),e.focus()}),a.on(o,function(e){i.close(k.index),t&&t(e.field)})}});k.index=l},C={html:'',strong:'',italic:'',underline:'',del:'',"|":'',left:'',center:'',right:'',link:'',unlink:'',face:'',image:'',code:'',help:''},L=new c;t(n,L)});layui.define("jquery",function(a){"use strict";var e=layui.$;a("code",function(a){var l=[];a=a||{},a.elem=e(a.elem||".layui-code"),a.lang="lang"in a?a.lang:"code",a.elem.each(function(){l.push(this)}),layui.each(l.reverse(),function(l,i){var t=e(i),c=t.html();(t.attr("lay-encode")||a.encode)&&(c=c.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")),t.html('
                    1. '+c.replace(/[\r\t\n]+/g,"
                    2. ")+"
                    "),t.find(">.layui-code-h3")[0]||t.prepend('

                    '+(t.attr("lay-title")||a.title||"</>")+''+(t.attr("lay-lang")||a.lang||"")+"

                    ");var n=t.find(">.layui-code-ol");t.addClass("layui-box layui-code-view"),(t.attr("lay-skin")||a.skin)&&t.addClass("layui-code-"+(t.attr("lay-skin")||a.skin)),(n.find("li").length/100|0)>0&&n.css("margin-left",(n.find("li").length/100|0)+"px"),(t.attr("lay-height")||a.height)&&n.css("max-height",t.attr("lay-height")||a.height)})})}).addcss("modules/code.css?v=1","skincodecss"); \ No newline at end of file diff --git a/ss-admin/src/main/resources/static/lib/qrcode/qrcode.min.js b/ss-admin/src/main/resources/static/lib/qrcode/qrcode.min.js new file mode 100644 index 0000000..993e88f --- /dev/null +++ b/ss-admin/src/main/resources/static/lib/qrcode/qrcode.min.js @@ -0,0 +1 @@ +var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j=0?p.get(q):0}}for(var r=0,m=0;mm;m++)for(var j=0;jm;m++)for(var j=0;j=0;)b^=f.G15<=0;)b^=f.G18<>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;cf;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=[''],h=0;d>h;h++){g.push("");for(var i=0;d>i;i++)g.push('');g.push("")}g.push("
                    "),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}(); \ No newline at end of file diff --git a/ss-admin/src/main/resources/templates/cloud/account/department/add.html b/ss-admin/src/main/resources/templates/cloud/account/department/add.html new file mode 100644 index 0000000..f956492 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/department/add.html @@ -0,0 +1,46 @@ + + + + + 添加信息 + + + + + + + + + + + +
                    +
                    +
                    +
                    + + +
                    + +
                    + +
                    +
                    +
                    +
                    +
                    +
                    + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/department/edit.html b/ss-admin/src/main/resources/templates/cloud/account/department/edit.html new file mode 100644 index 0000000..6cb238a --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/department/edit.html @@ -0,0 +1,66 @@ + + + + + 编辑信息 + + + + + + + + + + + +
                    +
                    +
                    + +
                    + + +
                    + +
                    + +
                    +
                    +
                    +
                    +
                    +
                    + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/department/index.html b/ss-admin/src/main/resources/templates/cloud/account/department/index.html new file mode 100644 index 0000000..3f2503d --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/department/index.html @@ -0,0 +1,210 @@ + + + + + 部门管理 + + + + + + +
                    +
                    + + + +
                    企业架构 +
                    +
                    +
                    +
                    +
                    + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/enterprise/add.html b/ss-admin/src/main/resources/templates/cloud/account/enterprise/add.html new file mode 100644 index 0000000..2c7307b --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/enterprise/add.html @@ -0,0 +1,43 @@ + + + + + 添加信息 + + + + + + + + + + + +
                    +
                    +
                    +
                    +
                    + +
                    + +
                    +
                    +
                    +
                    +
                    +
                    + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/enterprise/edit.html b/ss-admin/src/main/resources/templates/cloud/account/enterprise/edit.html new file mode 100644 index 0000000..485b889 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/enterprise/edit.html @@ -0,0 +1,60 @@ + + + + + 编辑信息 + + + + + + + + + + + +
                    +
                    +
                    +
                    +
                    + +
                    + +
                    +
                    +
                    +
                    +
                    +
                    + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/enterprise/index.html b/ss-admin/src/main/resources/templates/cloud/account/enterprise/index.html new file mode 100644 index 0000000..b3ecafa --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/enterprise/index.html @@ -0,0 +1,266 @@ + + + + + 企业管理 + + + + + + +
                    +
                    + +
                    + 搜索 +
                    +
                    + +
                    + +
                    + +
                    + +
                    + +
                    + + +
                    +
                    +
                    +
                    + +
                    +
                    +
                    + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/user/add.html b/ss-admin/src/main/resources/templates/cloud/account/user/add.html new file mode 100644 index 0000000..a6f8568 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/user/add.html @@ -0,0 +1,273 @@ + + + + + 添加用户 + + + + + + + + + + + +
                    +
                    +
                    + + +
                    + +
                    + +
                    + +
                    +
                    + +
                    + +
                    + +
                    +
                    +
                    + +
                    + +
                    + +
                    +
                    后台登录账号
                    +
                    + +
                    + +
                    + +
                    +
                    后台登录账号
                    +
                    + +
                    + +
                    + +
                    + +
                    +
                    + +
                    +
                    + +
                    + +
                    + +
                    +
                    +
                    + +
                    + +
                    +
                      +
                      +
                      + + + +
                      + +
                      +
                        +
                        +
                        + + +
                        + +
                        + +
                        +
                        + +
                        + +
                        +
                        +
                        +
                        + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/user/authRole.html b/ss-admin/src/main/resources/templates/cloud/account/user/authRole.html new file mode 100644 index 0000000..2def3cc --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/user/authRole.html @@ -0,0 +1,110 @@ + + + + + 分配角色 + + + + + + + + +
                        +
                        + +
                        +
                        + 用户信息 +
                        + +
                        + + +
                        + +
                        + + +
                        +
                        +
                        + +
                        + 角色列表 +
                        + +
                        + + +
                        +
                        +
                        + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/user/edit.html b/ss-admin/src/main/resources/templates/cloud/account/user/edit.html new file mode 100644 index 0000000..a9269e8 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/user/edit.html @@ -0,0 +1,136 @@ + + + + + 编辑用户 + + + + + + + + + + + +
                        +
                        +
                        + + +
                        + +
                        + +
                        + +
                        +
                        + +
                        + +
                        + +
                        +
                        +
                        + +
                        + +
                        + +
                        +
                        后台登录账号
                        +
                        + +
                        + +
                        + +
                        +
                        后台登录账号
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + +
                        +
                        +
                        +
                        + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/user/editDepartment.html b/ss-admin/src/main/resources/templates/cloud/account/user/editDepartment.html new file mode 100644 index 0000000..1bd9525 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/user/editDepartment.html @@ -0,0 +1,103 @@ + + + + + 部门管理 + + + + + + +
                        +
                        + + + +
                        企业架构 +
                        +
                        +
                        +
                        +
                        + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/user/index.html b/ss-admin/src/main/resources/templates/cloud/account/user/index.html new file mode 100644 index 0000000..67ebef9 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/user/index.html @@ -0,0 +1,511 @@ + + + + + 用户管理 + + + + + + +
                        +
                        +
                        企业架构
                        +
                        +
                        +
                        +
                        +
                        + +
                        + 搜索 +
                        +
                        +
                        + +
                        + +
                        + +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + + + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/user/selectDepartment.html b/ss-admin/src/main/resources/templates/cloud/account/user/selectDepartment.html new file mode 100644 index 0000000..321a864 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/user/selectDepartment.html @@ -0,0 +1,117 @@ + + + + + 部门管理 + + + + + + +
                        +
                        + + + +
                        企业架构 +
                        +
                        +
                        +
                        + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/account/user/updateDepartment.html b/ss-admin/src/main/resources/templates/cloud/account/user/updateDepartment.html new file mode 100644 index 0000000..50dbca2 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/account/user/updateDepartment.html @@ -0,0 +1,131 @@ + + + + + 部门管理 + + + + + + +
                        +
                        + + + +
                        企业架构 +
                        +
                        +
                        +
                        + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/collect/index.html b/ss-admin/src/main/resources/templates/cloud/collect/index.html new file mode 100644 index 0000000..7fe6838 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/collect/index.html @@ -0,0 +1,261 @@ + + + + + 企业文件 + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        + + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/lately/index.html b/ss-admin/src/main/resources/templates/cloud/lately/index.html new file mode 100644 index 0000000..e2ccd05 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/lately/index.html @@ -0,0 +1,231 @@ + + + + + 企业文件 + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        + + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/my/index.html b/ss-admin/src/main/resources/templates/cloud/my/index.html new file mode 100644 index 0000000..f2f04a9 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/my/index.html @@ -0,0 +1,333 @@ + + + + + 企业文件 + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        + + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/recycle/index.html b/ss-admin/src/main/resources/templates/cloud/recycle/index.html new file mode 100644 index 0000000..e3d10da --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/recycle/index.html @@ -0,0 +1,222 @@ + + + + + 企业文件 + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/role/role/add.html b/ss-admin/src/main/resources/templates/cloud/role/role/add.html new file mode 100644 index 0000000..60667b2 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/role/role/add.html @@ -0,0 +1,75 @@ + + + + + 添加信息 + + + + + + + + + + + +
                        +
                        +
                        +
                        +
                        + +
                        + +
                        +
                        +
                        + + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        +
                        +
                        + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/role/role/authUser.html b/ss-admin/src/main/resources/templates/cloud/role/role/authUser.html new file mode 100644 index 0000000..bdc3c43 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/role/role/authUser.html @@ -0,0 +1,209 @@ + + + + + 授权角色 + + + + + + +
                        +
                        +
                        +
                        + 角色信息 +
                        +
                        + + +
                        + +
                        + +
                        +
                        +
                        + +
                        + 已授权用户列表 +
                        + +
                        + + +
                        +
                        +
                        + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/role/role/edit.html b/ss-admin/src/main/resources/templates/cloud/role/role/edit.html new file mode 100644 index 0000000..a25321c --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/role/role/edit.html @@ -0,0 +1,108 @@ + + + + + 编辑信息 + + + + + + + + + + + +
                        +
                        +
                        +
                        +
                        + +
                        + +
                        +
                        +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        +
                        +
                        + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/role/role/index.html b/ss-admin/src/main/resources/templates/cloud/role/role/index.html new file mode 100644 index 0000000..95e187f --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/role/role/index.html @@ -0,0 +1,421 @@ + + + + + 权限管理 + + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        + +
                        + +
                        + +
                        + +
                        + +
                        + + +
                        +
                        +
                        +
                        + +
                        +
                        +
                        + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/share/index.html b/ss-admin/src/main/resources/templates/cloud/share/index.html new file mode 100644 index 0000000..bbb880e --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/share/index.html @@ -0,0 +1,610 @@ + + + + + 企业文件 + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        + + + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/space/file/add.html b/ss-admin/src/main/resources/templates/cloud/space/file/add.html new file mode 100644 index 0000000..3954d18 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/space/file/add.html @@ -0,0 +1,75 @@ + + + + + 添加信息 + + + + + + + + + + + +
                        +
                        +
                        +
                        +
                        + +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        +
                        +
                        + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/space/file/authFile.html b/ss-admin/src/main/resources/templates/cloud/space/file/authFile.html new file mode 100644 index 0000000..bc93808 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/space/file/authFile.html @@ -0,0 +1,131 @@ + + + + + 文件管理 + + + + + + +
                        +
                        + + + +
                        目录架构 +
                        +
                        +
                        +
                        +
                        + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/space/file/authRole.html b/ss-admin/src/main/resources/templates/cloud/space/file/authRole.html new file mode 100644 index 0000000..b11f095 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/space/file/authRole.html @@ -0,0 +1,97 @@ + + + + + 分配角色 + + + + + + + + +
                        +
                        + +
                        + +
                        + 角色列表 +
                        + +
                        + + +
                        +
                        +
                        + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/space/file/edit.html b/ss-admin/src/main/resources/templates/cloud/space/file/edit.html new file mode 100644 index 0000000..0313965 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/space/file/edit.html @@ -0,0 +1,108 @@ + + + + + 编辑信息 + + + + + + + + + + + +
                        +
                        +
                        +
                        +
                        + +
                        + +
                        +
                        +
                        + + +
                        +
                        +
                        + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/space/file/index.html b/ss-admin/src/main/resources/templates/cloud/space/file/index.html new file mode 100644 index 0000000..cab28b6 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/space/file/index.html @@ -0,0 +1,604 @@ + + + + + 企业文件 + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        + + + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/space/file/updateAuthFile.html b/ss-admin/src/main/resources/templates/cloud/space/file/updateAuthFile.html new file mode 100644 index 0000000..38074df --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/space/file/updateAuthFile.html @@ -0,0 +1,135 @@ + + + + + 文件管理 + + + + + + +
                        +
                        + + + +
                        目录架构 +
                        +
                        +
                        +
                        +
                        + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/space/recycle/index.html b/ss-admin/src/main/resources/templates/cloud/space/recycle/index.html new file mode 100644 index 0000000..d596a99 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/space/recycle/index.html @@ -0,0 +1,222 @@ + + + + + 企业文件 + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/upload/changeIndex.html b/ss-admin/src/main/resources/templates/cloud/upload/changeIndex.html new file mode 100644 index 0000000..326522c --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/upload/changeIndex.html @@ -0,0 +1,571 @@ + + + + + OSS多文件上传 + + + + + + +
                        +

                        拖拽文件上传到OSS

                        + + +
                        + +

                        将文件拖拽到此处上传

                        +

                        支持多个文件,最大1GB

                        +

                        支持图片、文档、压缩包等格式

                        +
                        + + +
                        +
                        + +

                        暂无文件,请拖拽文件到上方区域

                        +
                        +
                        + + + +
                        + + + + + + + diff --git a/ss-admin/src/main/resources/templates/cloud/upload/index.html b/ss-admin/src/main/resources/templates/cloud/upload/index.html new file mode 100644 index 0000000..50aecb1 --- /dev/null +++ b/ss-admin/src/main/resources/templates/cloud/upload/index.html @@ -0,0 +1,541 @@ + + + + + OSS多文件上传 + + + + + + +
                        +

                        拖拽文件上传到OSS

                        + + +
                        + +

                        将文件拖拽到此处上传

                        +

                        支持多个文件,最大1GB

                        +

                        支持图片、文档、压缩包等格式

                        +
                        + + +
                        +
                        + +

                        暂无文件,请拖拽文件到上方区域

                        +
                        +
                        + + + +
                        + + + + + + + diff --git a/ss-admin/src/main/resources/templates/component/alipay/index.html b/ss-admin/src/main/resources/templates/component/alipay/index.html new file mode 100644 index 0000000..2f01b41 --- /dev/null +++ b/ss-admin/src/main/resources/templates/component/alipay/index.html @@ -0,0 +1,307 @@ + + + + + 支付宝支付演示 + + + + + + + + + + + + +
                        +
                        +
                        +
                          +
                        • 支付配置
                        • +
                        • 扫码支付演示
                        • +
                        • 交易查询
                        • +
                        • 退款演示
                        • +
                        +
                        + +
                        +
                        + +
                        +
                        + 基本信息配置(必填) +
                        +
                        + +
                        + +
                        +
                        设置支付宝应用的appid
                        +
                        +
                        + +
                        + +
                        +
                        设置支付宝应用的名称
                        +
                        +
                        + +
                        + +
                        +
                        填写支付宝应用私钥(Java语言)
                        +
                        +
                        + 公钥模式(与证书模式二选一) +
                        +
                        + +
                        + +
                        +
                        填写支付宝公钥
                        +
                        + +
                        + 证书模式(与公钥模式二选一) +
                        +
                        + +
                        + +
                        +
                        填写支付宝的应用公钥证书文件路径
                        +
                        +
                        + +
                        + +
                        +
                        填写支付宝公钥证书文件路径
                        +
                        +
                        + +
                        + +
                        +
                        填写支付宝根证书文件路径
                        +
                        +
                        + 其他信息配置 +
                        +
                        + +
                        + +
                        +
                        AES密钥(接口内容加密方式)
                        +
                        +
                        + +
                        + +
                        +
                        必须为外网可访问的url,不能携带参数。公网域名必须为https
                        +
                        +
                        + +
                        + +
                        +
                        证书模式填写:openapi.alipay.com 沙箱环境填写:openapi.alipaydev.com
                        +
                        + +
                        +
                        + + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        + +
                        +
                        + 支付宝支付演示 +
                        +
                        + +
                        + +
                        +
                        输入商品名称
                        +
                        +
                        + +
                        + +
                        +
                        填写支付金额
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + +
                        +
                        + +
                        +
                        + 交易结果查询 +
                        +
                        + +
                        + +
                        +
                        输入商户单号
                        +
                        + +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +
                        商户单号在哪里?① 【扫码支付演示】页面有显示 ② 支付宝订单页面有显示
                        +
                        +
                        + +
                        +
                        + +
                        +
                        + 退款操作 +
                        +
                        + +
                        + +
                        +
                        输入商户单号
                        +
                        +
                        + +
                        + +
                        +
                        填写退款金额,不能大于实际支付金额
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +
                        商户单号在哪里?① 【扫码支付演示】页面有显示 ② 支付宝订单页面有显示
                        +
                        +
                        +
                        +
                        +
                        +
                        + + + + + + + diff --git a/ss-admin/src/main/resources/templates/component/qiniuOss/index.html b/ss-admin/src/main/resources/templates/component/qiniuOss/index.html new file mode 100644 index 0000000..1a59e8d --- /dev/null +++ b/ss-admin/src/main/resources/templates/component/qiniuOss/index.html @@ -0,0 +1,107 @@ + + + + + 七牛云文件存储服务 + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        + +
                        + +
                        + +
                        + +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + +
                        +
                        +
                        + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/component/wechatPay/index.html b/ss-admin/src/main/resources/templates/component/wechatPay/index.html new file mode 100644 index 0000000..3ffa378 --- /dev/null +++ b/ss-admin/src/main/resources/templates/component/wechatPay/index.html @@ -0,0 +1,279 @@ + + + + + 微信支付演示 + + + + + + +
                        +
                        +
                        +
                          +
                        • 支付配置
                        • +
                        • 扫码支付演示
                        • +
                        • 交易查询
                        • +
                        • 退款演示
                        • +
                        +
                        + +
                        +
                        + +
                        +
                        + 微信支付信息配置 +
                        +
                        + +
                        + +
                        +
                        设置微信公众号或者小程序等的appid
                        +
                        +
                        + +
                        + +
                        +
                        请填写微信支付商户号
                        +
                        +
                        + +
                        + +
                        +
                        设置APIv2密钥(微信支付商户密钥
                        +
                        + +
                        + +
                        + +
                        +
                        APIv3密钥(微信支付商户密钥
                        +
                        + +
                        + +
                        + +
                        +
                        apiclient_cert.p12证书文件的绝对路径
                        +
                        + +
                        + +
                        + +
                        +
                        apiclient_key.pem证书文件的绝对路径
                        +
                        + +
                        + +
                        + +
                        +
                        apiclient_cert.pem证书文件绝对路径
                        +
                        + +
                        + +
                        + +
                        +
                        必须为外网可访问的url,不能携带参数。公网域名必须为https
                        +
                        + + +
                        +
                        + + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        + +
                        +
                        + 微信扫码支付演示 +
                        +
                        + +
                        + +
                        +
                        输入商品名称
                        +
                        +
                        + +
                        + +
                        +
                        填写支付金额
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + +
                        +
                        + +
                        +
                        + 微信支付结果查询 +
                        +
                        + +
                        + +
                        +
                        输入商户单号
                        +
                        + +
                        +
                        + +
                        +
                        +
                        +
                        +
                        + +
                        +
                        + +
                        +
                        + 微信支付退款操作 +
                        +
                        + +
                        + +
                        +
                        输入商户单号
                        +
                        +
                        + +
                        + +
                        +
                        填写退款金额,不能大于实际支付金额
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + + + + + + + \ No newline at end of file diff --git a/ss-admin/src/main/resources/templates/error/404.html b/ss-admin/src/main/resources/templates/error/404.html new file mode 100644 index 0000000..619e3ff --- /dev/null +++ b/ss-admin/src/main/resources/templates/error/404.html @@ -0,0 +1,96 @@ + + + + + + + + + 404 + + + + + + +
                        + ...404 这个网页还没开发好... +

                        {{ time }}

                        +

                        {{ date }}

                        +
                        + + + + + + diff --git a/ss-admin/src/main/resources/templates/error/500.html b/ss-admin/src/main/resources/templates/error/500.html new file mode 100644 index 0000000..8b7764a --- /dev/null +++ b/ss-admin/src/main/resources/templates/error/500.html @@ -0,0 +1,10 @@ + + + + + 500错误 + + + + + \ No newline at end of file diff --git a/ss-admin/src/main/resources/templates/error/error.html b/ss-admin/src/main/resources/templates/error/error.html new file mode 100644 index 0000000..b3c593b --- /dev/null +++ b/ss-admin/src/main/resources/templates/error/error.html @@ -0,0 +1,64 @@ + + + + + + + 错误页面 + + + + + +
                        +
                        + +
                        +
                        +
                        + +
                        +

                        404

                        +
                        页面不存在
                        + + + + +
                        +
                        + + \ No newline at end of file diff --git a/ss-admin/src/main/resources/templates/file/pdf.html b/ss-admin/src/main/resources/templates/file/pdf.html new file mode 100644 index 0000000..dd108ef --- /dev/null +++ b/ss-admin/src/main/resources/templates/file/pdf.html @@ -0,0 +1,26 @@ + + + + + 企业文件 + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/advanced/generator.html b/ss-admin/src/main/resources/templates/system/advanced/generator.html new file mode 100644 index 0000000..b1d2fb9 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/advanced/generator.html @@ -0,0 +1,202 @@ + + + + + 代码生成 + + + + + +
                        +
                        + + +
                        +
                        +
                        + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/advanced/monitorServer.html b/ss-admin/src/main/resources/templates/system/advanced/monitorServer.html new file mode 100644 index 0000000..b296a10 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/advanced/monitorServer.html @@ -0,0 +1,264 @@ + + + + + 系统监控 - 服务器监控 + + + + + + +
                        +
                        +
                        +
                        服务器信息
                        +
                        + + + + + + + + + + + + + + + + + + + + + + + +
                        服务器名称服务器IP操作系统系统架构
                            
                        +
                        +
                        +
                        +
                        + +
                        +
                        +
                        +
                        CPU信息
                        +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        属性
                        核心数
                        用户使用率
                        系统使用率
                        当前空闲率
                        +
                        +
                        +
                        +
                        +
                        +
                        内存信息
                        +
                        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        属性内存JVM
                        总内存
                        已用内存
                        剩余内存
                        使用率
                        +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        +
                        Java虚拟机信息
                        +
                        + + + + + + + + + + + + + + + + + + + + + + + + + +
                        Java名称Java版本
                        安装路径启动时间
                        项目路径运行时长
                        +
                        +
                        +
                        +
                        + + +
                        +
                        +
                        +
                        磁盘信息
                        +
                        +
                        +
                        +
                        +
                        +
                        + + + + + + \ No newline at end of file diff --git a/ss-admin/src/main/resources/templates/system/index.html b/ss-admin/src/main/resources/templates/system/index.html new file mode 100644 index 0000000..fbfd734 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/index.html @@ -0,0 +1,177 @@ + + + + + 后台管理系统1.0 + + + + + + + + + + + + + + + + +
                        + +
                        + + + +
                        + +
                        +
                        + + +
                          +
                        + + + + + +
                        +
                        + + +
                        + +
                        + + +
                        +
                        +
                        + + +
                        + + +
                        + +
                        + +
                        +
                          +
                        • +
                        +
                        +
                      • +
                      • +
                      • + +
                      • +
                        +
                        +
                        +
                        +
                        + +
                        +
                        + + + + + diff --git a/ss-admin/src/main/resources/templates/system/log/login.html b/ss-admin/src/main/resources/templates/system/log/login.html new file mode 100644 index 0000000..27f4779 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/log/login.html @@ -0,0 +1,357 @@ + + + + + 登录日志 + + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        +
                        + + +
                        + +
                        + + +
                        + +
                        + + +
                        + +
                        +
                        -
                        +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + + +
                        + +
                        +
                        + + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/log/request.html b/ss-admin/src/main/resources/templates/system/log/request.html new file mode 100644 index 0000000..c9b7481 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/log/request.html @@ -0,0 +1,374 @@ + + + + + 操作日志 + + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        +
                        + + +
                        + +
                        + + +
                        + +
                        +
                        -
                        +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + + +
                        + +
                        +
                        + + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/login.html b/ss-admin/src/main/resources/templates/system/login.html new file mode 100644 index 0000000..a415df5 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/login.html @@ -0,0 +1,1024 @@ + + + + + + + + + + + + 领淘众创企业云盘 + + + + + + + + + + + + + +
                        + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/login1.html b/ss-admin/src/main/resources/templates/system/login1.html new file mode 100644 index 0000000..8b5a09b --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/login1.html @@ -0,0 +1,168 @@ + + + + + ExciteCMS - 后台登录 + + + + + + + + + + +
                        + +
                        + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/menu/add.html b/ss-admin/src/main/resources/templates/system/menu/add.html new file mode 100644 index 0000000..a667b0e --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/menu/add.html @@ -0,0 +1,283 @@ + + + + + 添加菜单 + + + + + + + + + + + + +
                        +
                        +
                        + +
                        + +
                        + + + + +
                        +
                        + + +
                        + +
                        + +
                        + +
                        +
                        + +
                        + +
                        + +
                        +
                        数值越大越靠前
                        +
                        +
                        + + +
                        + +
                        + +
                        + + +
                        +
                        + +
                        + +
                        + +
                        +
                        +
                        + + +
                        + +
                        + +
                        +
                        如:/system/menu/list
                        +
                        + + +
                        + +
                        + +
                        +
                        + + 如:system:menu:list +
                        +
                        + + +
                        + +
                        + + + + + 注:此操作设置点亮后不可逆! +
                        +
                        + +
                        + +
                        +
                        +
                        +
                        + + + + + \ No newline at end of file diff --git a/ss-admin/src/main/resources/templates/system/menu/edit.html b/ss-admin/src/main/resources/templates/system/menu/edit.html new file mode 100644 index 0000000..d348d5e --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/menu/edit.html @@ -0,0 +1,271 @@ + + + + + 编辑菜单 + + + + + + + + + + +
                        +
                        +
                        + + +
                        + +
                        + + + + +
                        +
                        + + +
                        + +
                        + +
                        + +
                        +
                        + +
                        + +
                        + +
                        +
                        数值越大越靠前
                        +
                        +
                        + + +
                        + +
                        + +
                        + + +
                        +
                        + +
                        + +
                        + +
                        +
                        +
                        + + +
                        + +
                        + +
                        +
                        如:/system/menu/list
                        +
                        + + +
                        + +
                        + +
                        +
                        + + 如:system:menu:list +
                        +
                        + + +
                        + +
                        + + + + + 注:此操作设置点亮后不可逆! +
                        +
                        +
                        + +
                        +
                        +
                        +
                        + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/menu/index.html b/ss-admin/src/main/resources/templates/system/menu/index.html new file mode 100644 index 0000000..1df95e5 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/menu/index.html @@ -0,0 +1,352 @@ + + + + + 菜单管理 + + + + + + +
                        +
                        +
                        + +
                        +
                        +
                        +
                        + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/role/add.html b/ss-admin/src/main/resources/templates/system/role/add.html new file mode 100644 index 0000000..d69b192 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/role/add.html @@ -0,0 +1,188 @@ + + + + + 添加菜单 + + + + + + + + + + + +
                        +
                        +
                        + +
                        + +
                        + +
                        + +
                        +
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + +
                        + +
                        +
                        如:admin
                        +
                        + +
                        + +
                        + +
                        + +
                        +
                        数值越大越靠前
                        +
                        +
                        + +
                        + +
                        + +
                        +
                        注:此操作设置点亮后不可逆!
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + +
                        +
                        +
                        +
                        + + + + + diff --git a/ss-admin/src/main/resources/templates/system/role/authUser.html b/ss-admin/src/main/resources/templates/system/role/authUser.html new file mode 100644 index 0000000..2b11c2d --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/role/authUser.html @@ -0,0 +1,261 @@ + + + + + 授权角色 + + + + + + +
                        +
                        +
                        +
                        + 角色信息 +
                        +
                        + +
                        + +
                        + +
                        +
                        + +
                        + +
                        + +
                        +
                        +
                        + +
                        + 已授权用户列表 +
                        + +
                        + + +
                        +
                        +
                        + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/role/edit.html b/ss-admin/src/main/resources/templates/system/role/edit.html new file mode 100644 index 0000000..da341e3 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/role/edit.html @@ -0,0 +1,189 @@ + + + + + 编辑菜单 + + + + + + + + + + + +
                        +
                        +
                        + + +
                        + +
                        + +
                        + +
                        +
                        +
                        + + +
                        + +
                        + +
                        +
                        + + +
                        + +
                        + +
                        +
                        + 如:admin +
                        +
                        + + +
                        + +
                        + +
                        + +
                        +
                        数值越大越靠前
                        +
                        +
                        + + +
                        + +
                        + +
                        +
                        + 注:此操作设置点亮后不可逆! +
                        +
                        + + +
                        + +
                        + +
                        +
                        + +
                        + +
                        +
                        +
                        +
                        + + + + + diff --git a/ss-admin/src/main/resources/templates/system/role/index.html b/ss-admin/src/main/resources/templates/system/role/index.html new file mode 100644 index 0000000..87d58ac --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/role/index.html @@ -0,0 +1,367 @@ + + + + + 角色管理 + + + + + +
                        +
                        + +
                        + 搜索 +
                        +
                        + +
                        + +
                        + +
                        + +
                        + +
                        +
                        + +
                        + + +
                        +
                        +
                        +
                        + +
                        +
                        +
                        + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/user/add.html b/ss-admin/src/main/resources/templates/system/user/add.html new file mode 100644 index 0000000..925b17e --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/user/add.html @@ -0,0 +1,235 @@ + + + + + 添加用户 + + + + + + + + + + + +
                        +
                        +
                        + +
                        + +
                        + +
                        + +
                        +
                        + +
                        + +
                        + +
                        +
                        +
                        + +
                        + +
                        + +
                        +
                        后台登录账号
                        +
                        + +
                        + +
                        + +
                        +
                        后台登录账号
                        +
                        + +
                        + +
                        + +
                        + +
                        +
                        + +
                        +
                        + +
                        + +
                        + +
                        +
                        +
                        + +
                        + +
                        +
                          +
                          +
                          + +
                          + +
                          + +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/user/authRole.html b/ss-admin/src/main/resources/templates/system/user/authRole.html new file mode 100644 index 0000000..96cfc0b --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/user/authRole.html @@ -0,0 +1,117 @@ + + + + + 分配角色 + + + + + + + + +
                          +
                          + +
                          +
                          + 用户信息 +
                          + +
                          + +
                          + +
                          + +
                          +
                          + +
                          + +
                          + +
                          +
                          +
                          + +
                          + 角色列表 +
                          + +
                          + + +
                          +
                          +
                          + + + + + \ No newline at end of file diff --git a/ss-admin/src/main/resources/templates/system/user/edit.html b/ss-admin/src/main/resources/templates/system/user/edit.html new file mode 100644 index 0000000..32b5b2d --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/user/edit.html @@ -0,0 +1,136 @@ + + + + + 编辑用户 + + + + + + + + + + + +
                          +
                          +
                          + + +
                          + +
                          + +
                          + +
                          +
                          + +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          + +
                          +
                          后台登录账号
                          +
                          + +
                          + +
                          + +
                          +
                          后台登录账号
                          +
                          + +
                          + +
                          + +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + + + + + diff --git a/ss-admin/src/main/resources/templates/system/user/index.html b/ss-admin/src/main/resources/templates/system/user/index.html new file mode 100644 index 0000000..be4ef82 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/user/index.html @@ -0,0 +1,429 @@ + + + + + 用户管理 + + + + + +
                          +
                          + +
                          + 搜索 +
                          +
                          +
                          + +
                          + +
                          + +
                          + +
                          +
                          + +
                          + + +
                          +
                          +
                          +
                          + +
                          +
                          +
                          + + + + + + + + + + + + diff --git a/ss-admin/src/main/resources/templates/system/userCenter/password.html b/ss-admin/src/main/resources/templates/system/userCenter/password.html new file mode 100644 index 0000000..c206eef --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/userCenter/password.html @@ -0,0 +1,70 @@ + + + + + 修改密码 + + + + + + + +
                          +
                          + +
                          +
                          + +
                          + + 填写自己账号的旧的密码。 +
                          +
                          + +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          +
                          +
                          + + + + + diff --git a/ss-admin/src/main/resources/templates/system/userCenter/setting.html b/ss-admin/src/main/resources/templates/system/userCenter/setting.html new file mode 100644 index 0000000..cd56b12 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/userCenter/setting.html @@ -0,0 +1,84 @@ + + + + + 基本资料修改 + + + + + + + + +
                          +
                          + +
                          +
                          + 我的基本资料 +
                          + +
                          + +
                          + + 请填写自己的账号名称。 +
                          +
                          + +
                          + +
                          + + 请填写登录账号! +
                          +
                          + +
                          + +
                          + +
                          +
                          + +
                          + +
                          + +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          +
                          +
                          + + + + + diff --git a/ss-admin/src/main/resources/templates/system/welcome.html b/ss-admin/src/main/resources/templates/system/welcome.html new file mode 100644 index 0000000..8605136 --- /dev/null +++ b/ss-admin/src/main/resources/templates/system/welcome.html @@ -0,0 +1,215 @@ + + + + + 首页 + + + + + + + + + + +
                          +
                          +
                          + +
                          + +
                          + + +
                          + +
                          + +
                          +
                          +
                          置顶文件
                          +
                          + +
                          +
                          +
                          +
                          +
                          + + +
                          + + + +
                          +
                          文件动态
                          +
                          + + + +
                          +
                          + +
                          +
                          +
                          +
                          + + + + + + diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/CodeGenerator.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/CodeGenerator.java new file mode 100644 index 0000000..e511632 --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/CodeGenerator.java @@ -0,0 +1,186 @@ +package com.zxdmy.excite.admin; + + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.generator.AutoGenerator; +import com.baomidou.mybatisplus.generator.InjectionConfig; +import com.baomidou.mybatisplus.generator.config.*; +import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; +import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; + +import java.util.*; + +/** + *

                          + * MP 代码生成器 + *

                          + * + * @author 沈松 + * @since 2021-09-01 0001 18:51 + */ +public class CodeGenerator { + /** + *

                          + * 读取控制台内容 + *

                          + */ + private static String scanner(String tip) { + Scanner scanner = new Scanner(System.in); + StringBuilder help = new StringBuilder(); + help.append("请输入").append(tip).append(":"); + System.out.println(help.toString()); + if (scanner.hasNext()) { + String ipt = scanner.next(); + if (StringUtils.isNotBlank(ipt)) { + return ipt; + } + } + throw new MybatisPlusException("请输入正确的" + tip + "!"); + } + + /** + * 执行此处 + */ + public static void main(String[] args) { + // 代码生成器 + AutoGenerator mpg = new AutoGenerator(); + + // 项目根目录 + String projectPath = System.getProperty("user.dir"); + System.out.println(projectPath); + // D:\IdeaProjects\2021_ExciteCMS\ExciteCMS + + String projectPack = "/src/main/java/com/zxdmy/excite/"; + + // 输入模块名 + String moduleName = scanner("模块名(系统端建议system,客户端建议client)"); + + // 六类文件的保存路径设置,可以根据自己项目的实际情况修改 + String entityPath = projectPath + "/ss-" + moduleName + projectPack + moduleName + "/entity/"; + String servicePath = projectPath + "/ss-" + moduleName + projectPack + moduleName + "/service/"; + String serviceImplPath = projectPath + "/ss-" + moduleName + projectPack + moduleName + "/service/impl/"; + String mapperPath = projectPath + "/ss-" + moduleName + projectPack + moduleName + "/mapper"; + String mapperXmlPath = projectPath + "/ss-" + moduleName + "/src/main/resources/mapper/"; + + String controllerPath = projectPath + "/ss-admin/src/main/java/com/zxdmy/excite/admin/controller/" + moduleName + "/"; + + // 1. 全局配置 + GlobalConfig globalConfig = new GlobalConfig(); + globalConfig + // TODO 代码生成的目录 +// .setOutputDir(projectPath + "/src/main/java") + .setAuthor("沈松") // TODO 修改项目作者 + .setOpen(false) // 是否打开输出目录 + .setIdType(IdType.ASSIGN_ID) // 主键策略 + .setFileOverride(false) // TODO 是否覆盖已有文件 + .setBaseResultMap(true) // 是否开启 BaseResultMap(XML文件) + .setBaseColumnList(true); // 是否开启 baseColumnList(XML文件) +// .setServiceName(""); + + //把全局配置添加到代码生成器主类 + mpg.setGlobalConfig(globalConfig); + + // 2. 数据源配置 + DataSourceConfig dsConfig = new DataSourceConfig(); + dsConfig + // 数据库链接URL + .setUrl("jdbc:mysql://localhost:3306/db_excite_cms?useUnicode=true&serverTimezone=UTC&useSSL=false&characterEncoding=utf8") + // .setSchemaName("public") //数据库 schema name + .setDbType(DbType.MYSQL) // 数据库类型 + // 数据库驱动,MySQL5.X:com.mysql.jdbc.Driver + .setDriverName("com.mysql.cj.jdbc.Driver") + .setUsername("chen") // TODO 数据库用户名 + .setPassword("123456"); // TODO 数据库密码 + + // 把数据源配置添加到代码生成器主类 + mpg.setDataSource(dsConfig); + + // 3. 包配置 + PackageConfig pkConfig = new PackageConfig(); + // 添加这个后 会以一个实体为一个模块 比如user实体会生成user模块 每个模块下都会生成三层 +// pkConfig.setModuleName(scanner("模块名(系统端建议system,客户端建议client)")); + // TODO 父包名。如果为空,将下面子包名必须写写完整的包路径。如果不为空,只需写子包名。 + pkConfig.setParent("com.zxdmy.excite") + // TODO 子包名 + .setEntity(moduleName + ".entity") // 实体类 Entity包名 + .setXml("mapper") // 持久层 Mapper.xml 包名 + .setMapper(moduleName + ".mapper") // 持久层 Mapper.java 包名 + .setService(moduleName + ".service") // 服务层 Service.java 包名 + .setServiceImpl(moduleName + ".service.impl") // 服务层 ServiceImpl.java 包名 + .setController("admin.controller." + moduleName); // 控制层 Controller.java 包名 + + //设置自定义输出目录(分布式项目使用) + Map pathInfo = new HashMap<>(); + + pathInfo.put(ConstVal.ENTITY_PATH, entityPath); + pathInfo.put(ConstVal.MAPPER_PATH, mapperPath); +// pathInfo.put(ConstVal.XML_PATH, mapperXmlPath); + pathInfo.put(ConstVal.SERVICE_PATH, servicePath); + pathInfo.put(ConstVal.SERVICE_IMPL_PATH, serviceImplPath); + pathInfo.put(ConstVal.CONTROLLER_PATH, controllerPath); + + pkConfig.setPathInfo(pathInfo); + + // 把包配置添加到代码生成器主类 + mpg.setPackageInfo(pkConfig); + + // 4. 自定义配置【这是MyBatisPlus 3.x 新增的】 + InjectionConfig cfg = new InjectionConfig() { + @Override + public void initMap() { + // to do nothing + } + }; +// 如果模板引擎是 freemarker + String templatePath = "/templates/mapper.xml.ftl"; +// 如果模板引擎是 velocity +// String templatePath = "/templates/mapper.xml.vm"; + +// 自定义输出配置 + List focList = new ArrayList<>(); + // 自定义配置会被优先输出 + focList.add(new FileOutConfig(templatePath) { + @Override + public String outputFile(TableInfo tableInfo) { + // 自定义输出文件名称,如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!! +// return projectPath + "/ss-" + moduleName + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; + return mapperXmlPath + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; + } + }); + cfg.setFileOutConfigList(focList); + mpg.setCfg(cfg); + // 配置模板 + TemplateConfig templateConfig = new TemplateConfig(); + templateConfig.setXml(null); + mpg.setTemplate(templateConfig); + + // 5. 策略配置(数据库表配置) + StrategyConfig strategyConfig = new StrategyConfig(); + + strategyConfig + .setNaming(NamingStrategy.underline_to_camel) // 数据库表映射到实体的命名策略:下划线转驼峰 + .setColumnNaming(NamingStrategy.underline_to_camel) // 数据库表字段映射到实体的命名策略:下划线转驼峰 + .setEntityLombokModel(true) // 实体是否为lombok模型(默认 false) + // .setSuperEntityClass("com.zxdmy.wx.mp.wechat.common.BaseEntity") // 设置实体类的父类(如果启用,实体类会增加BaseEntity的继承) + .setSuperControllerClass("com.zxdmy.excite.common.base.BaseController") // 设置控制类的父类(如果启用,控制类会增加BaseController的继承) + // 提示输入生成的表名 + .setInclude(scanner("表全名,多个英文名称,使用英文逗号间隔").split(",")) + // .setExclude("***") // 需要排除的表名,允许正则表达式 + // .setSuperEntityColumns("id"); // 实体类主键名称设置(如果启用,生成的实体类没有此字段) + // .setTablePrefix(pc.getModuleName() + "_") // 表前缀符(如果启用,生成的所有文件名没有此前缀) + .setControllerMappingHyphenStyle(true); // 驼峰转连字符 + + // 把数据库配置添加到代码生成器主类 + mpg.setStrategy(strategyConfig); + + // 在代码生成器主类上配置模板引擎,选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有! + mpg.setTemplateEngine(new FreemarkerTemplateEngine()); + // 开始执行 + mpg.execute(); + } +} diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/ExciteAdminApplicationTests.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/ExciteAdminApplicationTests.java new file mode 100644 index 0000000..4dfe9fb --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/ExciteAdminApplicationTests.java @@ -0,0 +1,13 @@ +package com.zxdmy.excite.admin; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ExciteAdminApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/RsaTest.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/RsaTest.java new file mode 100644 index 0000000..f0d96ba --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/RsaTest.java @@ -0,0 +1,31 @@ +package com.zxdmy.excite.admin; + +import cn.hutool.crypto.asymmetric.RSA; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * RAS加密公钥、私钥生成测试类 + * + * @author 沈松 + * @since 2022/1/28 23:20 + */ +@SpringBootTest +public class RsaTest { + + @Test + void createKey() { + // 定义对象 + RSA rsa = new RSA(); + + //获得私钥 + System.out.println("私钥如下:"); + String privateKey = rsa.getPrivateKeyBase64(); + System.out.println(privateKey); + + //获得公钥 + System.out.println("公钥如下:"); + String publicKey = rsa.getPublicKeyBase64(); + System.out.println(publicKey); + } +} diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/SmartDocGenerator.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/SmartDocGenerator.java new file mode 100644 index 0000000..8c3570d --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/SmartDocGenerator.java @@ -0,0 +1,60 @@ +package com.zxdmy.excite.admin; + +import com.power.doc.builder.HtmlApiDocBuilder; +import com.power.doc.constants.DocGlobalConstants; +import com.power.doc.constants.DocLanguage; +import com.power.doc.model.ApiConfig; +import com.power.doc.model.ApiErrorCode; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; + +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * SmartDoc 接口文档生成工具 + *

                          + * + * @author 沈松 + * @since 2021-09-10 0010 23:55 + */ + +@SpringBootTest +public class SmartDocGenerator { + + @Test + public void generatorDoc() { + // 定义API配置对象 + ApiConfig config = new ApiConfig(); + // 设置项目根路径,将与控制类的路径对接 + config.setServerUrl("http://localhost:8181"); + // 当AllInOne为true,则将所有接口保存至一个文档中 + config.setAllInOne(true); + // 生成HTML文档保存路径。 + config.setOutPath(DocGlobalConstants.HTML_DOC_OUT_PATH); + // Smart-doc提供的常量HTML_DOC_OUT_PATH,是将文档保存至项目的 src/main/resources/static/doc 路径下。 + // 保存至此路径的好处是,生成文档之后,重新运行项目,访问 http://localhost:8181/doc/index.html 可以访问接口文档。 + + config.setLanguage(DocLanguage.CHINESE); + // 设置接口包扫描路径过滤,默认扫描所有的接口类。多个包名用英文逗号隔开。 + // config.setPackageFilters("com.zxdmy.excite.user"); + + + // 设置错误码列表(即遍历自己的错误码列表,赋值给接口文档) + List errorCodeList = new ArrayList<>(); + // 这里先使用HttpStatus的状态码 + for (HttpStatus httpStatus : HttpStatus.values()) { + ApiErrorCode errorCode = new ApiErrorCode(); + errorCode.setValue(String.valueOf(httpStatus.value())).setDesc(httpStatus.getReasonPhrase()); + errorCodeList.add(errorCode); + } + + // 设置错误码。如果不需要显示状态码,则不需要设置。 + config.setErrorCodes(errorCodeList); + // 生成HTML格式文档 + HtmlApiDocBuilder.buildApiDoc(config); + + } +} diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/component/AlipayTest.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/component/AlipayTest.java new file mode 100644 index 0000000..e9f7008 --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/component/AlipayTest.java @@ -0,0 +1,95 @@ +package com.zxdmy.excite.admin.component; + +import cn.hutool.core.util.IdUtil; +import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.zxdmy.excite.component.alipay.AlipayService; +import com.zxdmy.excite.component.bo.AlipayBO; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.Arrays; + +/** + *

                          + * 描述 + *

                          + * + * @author 沈松 + * @since 2022/1/11 11:42 + */ +@SpringBootTest +public class AlipayTest { + + + @Autowired + private AlipayService alipayService; + + @Test + void saveTest() { + AlipayBO alipayBO = new AlipayBO() + // 基本信息 + .setAppId("20210058") + .setAppName("沙箱测试应用") + .setMerchantPrivateKey("MIIEvAUpFY8wf6zJVf22u2kNomfr6+amzTzYE31j47jpOSNnB01zv8jiEFBWvGHLqeFU3eNpsen2HUbbP7drl58z9RhliJIamZ1+UXR4vV+3pzzd32oXUSUId35fjEYGiwPwy0LAqXn2kFD7Txk4kiw5sP1xdv4YIEEGWHrOtN9fznt6vNqY9BWyZCDMJ46SqWBqHY7XVemP991JgDa1HdFVsy6SnTMChhDLGcR3ND0+EdsYYv6MeNV89xdeakmXNQUFZ3KPFYnBhMnY01u4Gb6lZAZQA2zrhIS1CSERCsRLyqd/DmX5hX3U7JAgMBAAECggEAXxat7xpuR9XhoHHuCvyA1AhHLlu3Zvsz9xbzzi0G8gpcYDgno+vc86yrwtPgWb00Ef5ajhOL0fiFkn8Hpr3S4QqaxFSgnu5i5epV8FhAJg2xTuzzeiN7hFg64UG2ZH0bBW32qCPaPl0kS6LrlFkhKNh6LmUFotD6yzyBeK8U6BWEIq07KOKB0nW16duQ8BDj9BwLcyOjYLCIUccK0Z3+N5KVr2aJev6LZcNwZuXhdk4s1tGnX2dn9ATGi5xNFBDBS0nnCdAYnIYddNbozWJvSqqHJ0igaSOmO14dZBnpElY4vA3zXTsglV3A6BjMq4ahjG2crHA3ZQvgFXZ2QCY7gQKBgQDc19nWcQHJB3mvEg1DAdXZ5VBoy1Yo2sRAsjzffS7dUcPfEEod1VTgpxolv8awNxmge1wUYhZfGEb+cJacmYFTjyxKzUQreCKaIwqlKd+TsCLsviDvGzsMcKmhWe+JAAXZnTtsv/aVCGzN8ziOulDAkD7KRbyp2Uf2ekOWTEDAOQKBgQDBb8DNCY7pDU9/Dz11RMA0QOdhpWfvmv5ysYhq9wnTcmad3ySJvj83+Bf/OsASqcDY9w8mVKoVSVFhIfAH5ML1f5jSWkGSxyZQnQoh1pBBbG7bUIanTnsDy7hch/iGk/N9UN/kFak6fLBHVlnI+qfniAcJiNy03FaxwclMKg7jEQKBgCxybO9R0zAohv8LPQwNZIL0Ohi9Q9v5G6KBvOqmATad7DQKzT/v3aNRPlv2mwCANnIsIb4gd6wv8Kno8wcVhgfROvLbGSs+hIhNISlYohzRSFYpdetpqZq5WgqVVTZXgNXpZTpf8DrSdUOF/g4LxZDb9ycyneP5TRh4Rv4K3sVRAoGATVoB8Dv1QO6IrpeKjP1cGsklfZ+mK2OAgp7JnXSCImLp9BGKS+ae4yO7fN2idxQYwOoyzbInfXGfMEdg89cfuwo2M0/STv6CLNRPe+6QKwlQXzUZU4gHmyH47E+XK0G4qZEQpuWekXvRBgXay4qoX+a+YaqwD0bZCCYk9+cNovECgYBnJ+ez1B4YcADmNruPhKLiQ0/RkkuaGl8+CqslGhXJ4rqlS9u7uA66EDD3A5Fn1DX89i3wMYIVU0M8PCC2VBz8q4KdIPzRVe+NcFVTdOvDqr4dxrDhpu//HKQJFpwtildby2/MArP7HGDDI6oVhzd70ij/TzprmsRMvxC315+TJA==") + // 证书模式 + .setMerchantCertPath("E:\\支付宝支付\\appCertPublicKey_2021000117696058.crt") + .setAlipayCertPath("E:\\支付宝支付\\alipayCertPublicKey_RSA2.crt") + .setAlipayRootCertPath("E:\\支付宝支付\\alipayRootCert.crt") + // 接口内容加密方式 + .setEncryptKey("cAikHtKWeTYvCvw==") + // 注意:沙箱环境下,请配置此网关!正式环境可忽略! + .setGatewayHost("openapi.alipaydev.com"); + alipayService.saveConfig(alipayBO); + } + + /** + * 支付测试 + */ + @Test + void payTest() { + String outTradeNo = IdUtil.simpleUUID(); + System.out.println(outTradeNo); + System.out.println(alipayService.pay(null, "page", "测试商品名称", outTradeNo, "6666", "https://www.zxdmy.com", "https://www.zxdmy.com")); + } + + /** + * 查询测试 + */ + @Test + void queryTest() { + System.out.println(Arrays.toString(alipayService.queryPay(null, "2022011122001428220502263620", "f9bd5856549b47b684284816ac324f8c"))); + // [Y, 2022011122001428220502263620, f9bd5856549b47b684284816ac324f8c, TRADE_SUCCESS, 666.00, 2088622956328227, aev***@sandbox.com] + } + + /** + * 退款测试 + */ + @Test + void refundTest() { + System.out.println( + Arrays.toString(alipayService + .refund(null, "2022011122001428220502263620", null, "20.00", "不想要了"))); + // [Y, 2022011122001428220502263620, f9bd5856549b47b684284816ac324f8c, da7486bdbfe644c48c815af84af423cd, 10.00] + // [Y, 2022011122001428220502263620, f9bd5856549b47b684284816ac324f8c, 1dde059885134947948197f3b3268cf0, 30.00] + } + + /** + * 查询退款测试 + */ + @Test + void queryRefundTest() { + System.out.println(Arrays.toString(alipayService.queryRefund( + null, + "f9bd5856549b47b684284816ac324f8c0", + null))); + // [Y, 2022011122001428220502263620, f9bd5856549b47b684284816ac324f8c, da7486bdbfe644c48c815af84af423cd, 666.00, 10.00, null] + // [Y, 2022011122001428220502263620, f9bd5856549b47b684284816ac324f8c, 1dde059885134947948197f3b3268cf0, 666.00, 20.00, null] + } + + @Test + void downLoadTest() { + System.out.println(Arrays.toString(alipayService.downloadBill(null, "2021-12"))); + } +} diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/component/AliyunSmsTest.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/component/AliyunSmsTest.java new file mode 100644 index 0000000..71f1b84 --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/component/AliyunSmsTest.java @@ -0,0 +1,78 @@ +package com.zxdmy.excite.admin.component; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.zxdmy.excite.component.aliyun.AliyunSmsService; +import com.zxdmy.excite.component.bo.AliyunSmsBO; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.HashMap; +import java.util.Map; + + +/** + *

                          + * 阿里云短信服务测试类 + *

                          + * + * @author 沈松 + * @since 2022/1/3 16:40 + */ +@SpringBootTest +public class AliyunSmsTest { + + + @Autowired + private AliyunSmsService aliyunSmsService; + + /** + * 保存配置信息测试 + * + * @throws JsonProcessingException 异常 + */ + @Test + void saveTest() throws JsonProcessingException { + // 初始数据定义 + AliyunSmsBO aliyunSmsVO = new AliyunSmsBO() + .setKey("aliyunSms01") + .setAccessKeyId("********") + .setAccessKeySecret("*******") + .setSignName("中国移动") + .setTemplateCode("SMS_18*****22") + .setTemplateParam(new String[]{"username", "filename", "password"}); + aliyunSmsService.saveAliyunSmsConfig(aliyunSmsVO); + } + + /** + * 读取配置信息测试 + */ + @Test + void getTest() { + AliyunSmsBO aliyunSmsVO = aliyunSmsService.getAliyunSmsConfig("aliyunSms01"); + System.out.println(aliyunSmsVO); + + } + + /** + * 单个发送测试 + */ + @Test + void sendTest() { + Boolean result = aliyunSmsService.sendSmsOne("aliyunSms01", "15900889977", new String[]{"张三", "9月发票", "123456"}); + } + + /** + * 批量发送测试 + */ + @Test + void sendBatchTest() { + Map map = new HashMap<>(); + map.put("15900889977", new String[]{"张三", "9月发票", "123456"}); + map.put("18800889977", new String[]{"李四", "10月发票", "234567"}); + map.put("18900889977", new String[]{"王五", "11月发票", "345678"}); + Map mapResult = aliyunSmsService.sendSmsBatch("aliyunSms01", map); + } + + +} diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/component/WeChatPayTest.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/component/WeChatPayTest.java new file mode 100644 index 0000000..4bd87ff --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/component/WeChatPayTest.java @@ -0,0 +1,68 @@ +package com.zxdmy.excite.admin.component; + +import cn.hutool.core.lang.UUID; +import cn.hutool.core.util.IdUtil; +import cn.hutool.crypto.SecureUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.zxdmy.excite.component.bo.WeChatPayBO; +import com.zxdmy.excite.component.wechat.WeChatPayService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * 微信支付测试类 + * + * @author 沈松 + * @since 2022/1/10 16:26 + */ +@SpringBootTest +public class WeChatPayTest { + + @Autowired + private WeChatPayService weChatPayService; + + @Test + void saveTest() throws JsonProcessingException { + WeChatPayBO weChatPayBO = new WeChatPayBO(); + weChatPayBO.setAppId("") + .setMchId("") + .setMchKey("") + .setApiV3Key("") + .setKeyPath("E:\\微信支付\\Cert\\apiclient_cert.p12") + .setPrivateKeyPath("E:\\微信支付\\Cert\\apiclient_key.pem") + .setPrivateCertPath("E:\\微信支付\\Cert\\apiclient_cert.pem") + .setNotifyUrl("https://demo.zxdmy.com/notify"); + if (weChatPayService.saveConfig(weChatPayBO)) + System.out.println("成功!"); + + } + + @Test + void getTest() { + System.out.println(weChatPayService.getConfig()); + } + + @Test + void unifiedOrderTest2() throws WxPayException { + String result = weChatPayService.pay( + null, "jsapi", "商品标题", IdUtil.simpleUUID(), 1, "od0Pf5yi7sdBXm95fT786tdqtLgA" + ); + System.out.println(result); + } + + @Test + void queryTest() { +// 375f1b3a8f3f4f2aa6f086575f168096 + // 4200001322202201105842754907 + System.out.println(weChatPayService.query(null, "4200001322202201105842754907", null)); + } + + @Test + void refundTest() throws WxPayException { + System.out.println(weChatPayService.refund(null, "a4d798f07f8e4304bc0023e6ad4d3c5a", IdUtil.simpleUUID(), 1, 1)); + } +} diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/service/IGlobalConfigServiceTest.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/service/IGlobalConfigServiceTest.java new file mode 100644 index 0000000..9beabc4 --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/service/IGlobalConfigServiceTest.java @@ -0,0 +1,71 @@ +package com.zxdmy.excite.admin.service; + +import com.qiniu.storage.model.FileInfo; +import com.zxdmy.excite.component.qiniu.QiniuOssService; +import com.zxdmy.excite.component.bo.QiniuOssBO; +import com.zxdmy.excite.common.service.IGlobalConfigService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +/** + *

                          + * 描述 + *

                          + * + * @author 沈松 + * @since 2022/1/3 16:40 + */ +@SpringBootTest +public class IGlobalConfigServiceTest { + + @Autowired + private IGlobalConfigService componentConfigService; + + @Autowired + private QiniuOssService qiniuOssService; + +// @Test +// void saveTest() { +// // 初始数据定义 +// QiniuVO qiniuEntity = new QiniuVO(); +// qiniuEntity.setAccessKey("8bI0GWOa8888888888"); +// qiniuEntity.setSecretKey("WzYdBI8FL9999999999999999999"); +// qiniuEntity.setDomain("666.hd-bkt.clouddn.com"); +// qiniuEntity.setBucket("test-spring"); +// qiniuEntity.setRegion("z0"); +// qiniuEntity.setProtocol("http"); +// +// try { +// componentConfigService.save("qiniu", "qiniuOss", qiniuEntity, true); +// } catch (JsonProcessingException e) { +// e.printStackTrace(); +// } +// } + + @Test + void getTest() { + // 初始数据定义s + QiniuOssBO qiniuEntity = new QiniuOssBO(); + + qiniuEntity = (QiniuOssBO) componentConfigService.get("qiniu", "qiniuOss", qiniuEntity); + + System.out.println(qiniuEntity); + } + + @Test + void getList() { + List fileInfoList = qiniuOssService.getQiniuFileListAll("", ""); + for (FileInfo fileInfo : fileInfoList) { + System.out.println(fileInfo); + } + } + + @Test + void testtt() { + String url = qiniuOssService.getDownloadUrl("audio/song.mp3", "这是一首歌曲.mp3", 3600L); + System.out.println(url); + } +} diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/service/ISysMenuServiceTest.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/service/ISysMenuServiceTest.java new file mode 100644 index 0000000..1a303f7 --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/service/ISysMenuServiceTest.java @@ -0,0 +1,44 @@ +package com.zxdmy.excite.admin.service; + +import com.zxdmy.excite.system.entity.SysMenu; +import com.zxdmy.excite.system.mapper.SysMenuMapper; +import com.zxdmy.excite.system.service.ISysMenuService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +/** + *

                          + * 描述 + *

                          + * + * @author 沈松 + * @since 2021-09-23 0023 20:05 + */ +@SpringBootTest +class ISysMenuServiceTest { + + @Autowired + private ISysMenuService menuService; + + @Autowired + private SysMenuMapper menuMapper; + + @Test + void deleteTest() { + Integer id = null; + menuService.deleteMenu(id); + } + + @Test + void selectTest() { + Integer id = 10000; + List sysMenus = menuMapper.selectMenusByUserId(id, 0); + System.out.println(sysMenus); + + } + + +} diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/service/ISysUserServiceTest.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/service/ISysUserServiceTest.java new file mode 100644 index 0000000..e30cc59 --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/service/ISysUserServiceTest.java @@ -0,0 +1,250 @@ +package com.zxdmy.excite.admin.service; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.stp.StpLogic; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.asymmetric.ECIES; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.power.common.util.RSAUtil; +import com.zxdmy.excite.framework.oshi.Server; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.mapper.SysUserMapper; +import com.zxdmy.excite.system.service.ISysUserService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.util.DigestUtils; + +import java.security.KeyPair; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + *

                          + * 描述 + *

                          + * + * @author 沈松 + * @since 2021-09-01 0001 19:19 + */ +@SpringBootTest +class ISysUserServiceTest { + + @Autowired + private SysUserMapper userMapper; + + @Autowired + private ISysUserService userService; + + + @Test + void ServerTest() throws Exception { + Server server = new Server(); + server.copyTo(); + System.out.println(server); + } + + /** + * 生成密钥对 + */ + @Test + void RSA() { + + + String en = "EH5BLHO6HQGERUoJGzJxE4rX8SRC5j9fDkgN2lu7sSWHv5fHpIjg9Mct6Qbe3NO9nUlmpjsb0j+veiebK3g5so8EXkM71uUvCiq3zVX0hrLOWFBIi9/ikzrXFkxtFLfUIVhchuRncozQTZOux7QyOTBPFUdR2s3A8A80fWLZkfg="; + String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALwcyvYIGmhk+be320JWWsq1OYjiM0lzv8eHGMgSIOMLxzM/g9X7jguNe8thxJXR/CLqcTgsfZzk8E8Sc9+qnSDxNl5f5tga93vRxd5713zAeAGqLiTQnRffdzRmdbsmu5+0/K8mj056VhKh8FdBNzAj7e4iX9i+uBBG/oDmZbTVAgMBAAECgYEAmgNU5NTDkj9B+Pnt6UU8doSjw3+3j+bV2K2yS3QUOvAUus/Ax7x6ktjWxzCXvDY9IfUil2RNv9vtKEAqYLCWjc+lf8PV/yH1b7NEgyeAPBXtAJRoOnmYL2bdPW92kP9KgxJruF6Dz/C5AmMOncsvq8ABD+9Darn4p8dwj2ZC4O0CQQDf/AHmZsQokEItfCy4mHS9UbxbfIhEUv1ApPh/+Sr7NkJkHWYCtBQo+8jKO6zurAZQgWBPD1XX2UE4R+VIiZazAkEA1wAqtMvGhccyRZr+6kpkpDIa8+9jOE+nGUzqTDvgCID6as8AzOONFVVK6m/UUqkhcJ8Qu1pF36BGojy5BX2KVwJBAJSFpbji0hXXupowqfLp3RcgmNbNWAp+QUJZYhJx5cdYbmO2fssyH+AhPT6knYJR/YnqkDM8hv6vKCkqu2YDHjMCQAOA8TE5EOclM+CGghj3VWSHnIDVKdzFD4gOBNNxNlltIKeU8AJmwunSFgJ0CBXAw9a+ANvMwM7AIeaK7sj0HskCQAvxfDCq7gaNx+pfu0FHG8Gix08A/A6foggBl1fVu+L9sr9ZuOQ3HbXnl28F9ewuB9xdjnLUDjp7W7U0pB+vKoQ="; + + System.out.println(RSAUtil.decryptString(en, PRIVATE_KEY)); + + + // 原始字符串 +// String origin = "哈哈哈哈哈啊啊"; +// System.out.println("原始字符串:"); +// System.out.println(origin); + +// // 定义对象 +// RSA rsa = new RSA(); +// +// //获得私钥 +//// System.out.println(rsa.getPrivateKey()); +// System.out.println("私钥如下:"); +// String privateKey = rsa.getPrivateKeyBase64(); +// System.out.println(privateKey); +// +// //获得公钥 +//// System.out.println(rsa.getPublicKey()); +// System.out.println("公钥如下:"); +// String publicKey = rsa.getPublicKeyBase64(); +// System.out.println(publicKey); +// +// // 使用公钥进行加密 +// byte[] encrypt = rsa.encrypt(StrUtil.bytes(origin, CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey); +// // 加密结果 +// System.out.println("加密后的密文:"); +// String en = StrUtil.str(encrypt, CharsetUtil.CHARSET_UTF_8); +// System.out.println(en); +// +// // 使用私钥解密 +// byte[] decrypt = rsa.decrypt(en, KeyType.PrivateKey); + +// String en = "EH5BLHO6HQGERUoJGzJxE4rX8SRC5j9fDkgN2lu7sSWHv5fHpIjg9Mct6Qbe3NO9nUlmpjsb0j+veiebK3g5so8EXkM71uUvCiq3zVX0hrLOWFBIi9/ikzrXFkxtFLfUIVhchuRncozQTZOux7QyOTBPFUdR2s3A8A80fWLZkfg="; +// String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALwcyvYIGmhk+be320JWWsq1OYjiM0lzv8eHGMgSIOMLxzM/g9X7jguNe8thxJXR/CLqcTgsfZzk8E8Sc9+qnSDxNl5f5tga93vRxd5713zAeAGqLiTQnRffdzRmdbsmu5+0/K8mj056VhKh8FdBNzAj7e4iX9i+uBBG/oDmZbTVAgMBAAECgYEAmgNU5NTDkj9B+Pnt6UU8doSjw3+3j+bV2K2yS3QUOvAUus/Ax7x6ktjWxzCXvDY9IfUil2RNv9vtKEAqYLCWjc+lf8PV/yH1b7NEgyeAPBXtAJRoOnmYL2bdPW92kP9KgxJruF6Dz/C5AmMOncsvq8ABD+9Darn4p8dwj2ZC4O0CQQDf/AHmZsQokEItfCy4mHS9UbxbfIhEUv1ApPh/+Sr7NkJkHWYCtBQo+8jKO6zurAZQgWBPD1XX2UE4R+VIiZazAkEA1wAqtMvGhccyRZr+6kpkpDIa8+9jOE+nGUzqTDvgCID6as8AzOONFVVK6m/UUqkhcJ8Qu1pF36BGojy5BX2KVwJBAJSFpbji0hXXupowqfLp3RcgmNbNWAp+QUJZYhJx5cdYbmO2fssyH+AhPT6knYJR/YnqkDM8hv6vKCkqu2YDHjMCQAOA8TE5EOclM+CGghj3VWSHnIDVKdzFD4gOBNNxNlltIKeU8AJmwunSFgJ0CBXAw9a+ANvMwM7AIeaK7sj0HskCQAvxfDCq7gaNx+pfu0FHG8Gix08A/A6foggBl1fVu+L9sr9ZuOQ3HbXnl28F9ewuB9xdjnLUDjp7W7U0pB+vKoQ="; +// +// +// // 根据私钥生成新的对象 +// RSA rsa2 = new RSA(PRIVATE_KEY, null); +// byte[] decrypt = rsa2.decrypt(en, KeyType.PrivateKey); +// +// System.out.println("解密后的密文:"); +// System.out.println(StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8)); + + + } + + /** + * 测试添加一个用户 + */ +// @Test +// void createOneTest() { +// SysUser user = new SysUser(); +// user.setUsername("张三"); +// user.setEmail("1000@zxdmy.com"); +// user.setPassword("sfdnfjdsfhdsjk"); +// if (userService.save(user)) { +// System.out.println("新增用户成功"); +// } else { +// System.out.println("新增用户失败"); +// } +// } + @Test + void tokenTest() { + // 查询value包括1000的所有token,结果集从第0条开始,返回10条 + System.out.println(); + List tokenList = StpUtil.searchTokenValue("", 0, 10); + for (String token : tokenList) { + System.out.println(token); + } + System.out.println(); + List tokenList2 = StpUtil.searchTokenSessionId("", -1, 10000); + for (String token : tokenList2) { + System.out.println(token); + } + System.out.println(); + List tokenList3 = StpUtil.searchSessionId("", 0, 10000); + for (String token : tokenList3) { + + System.out.println(token); + } + +// List sessionIds = StpUtil.searchTokenValue(null, -1, 1000); +// MySaTokenListener.ONLINE_USERS.sort((o1, o2) -> DateUtil.compare(o2.getLoginTime(), o1.getLoginTime())); +// PageDtoUtil pageDto = PageDtoUtil.getPageDto(MySaTokenListener.ONLINE_USERS, page, limit); +// +// List pageList = (List) pageDto.getPageList(); +// pageList.forEach(onlineUser -> { +// String keyLastActivityTime = StpUtil.stpLogic.splicingKeyLastActivityTime(onlineUser.getTokenValue()); +// String lastActivityTimeString = SaManager.getSaTokenDao().get(keyLastActivityTime); +// if (lastActivityTimeString != null) { +// long lastActivityTime = Long.parseLong(lastActivityTimeString); +// onlineUser.setLastActivityTime(DateUtil.date(lastActivityTime)); +// } +// }); +// return PageResponse.ok(pageList, (long) pageDto.getTotal()); + + } + + /** + * 测试添加一系列数据 + */ +// @Test +// void createListTest() { +// // 定义用户列表 +// List userList = new ArrayList<>(); +// // 随机生成 5个用户 +// for (int i = 1; i <= 5; i++) { +// // 定义用户实体 +// SysUser user = new SysUser(); +// // 随机填充数据 +// user.setUsername("用户" + i); +// user.setEmail("1000@zxdmy.com" + i); +// user.setPassword(DigestUtils.md5DigestAsHex(("password" + i).getBytes())); +// // 添加至列表 +// userList.add(user); +// } +// // 打印用户列表 +// System.out.println(userList); +// // 执行添加 +// if (userService.saveBatch(userList)) { +// System.out.println("新增用户成功"); +// } else { +// System.out.println("新增用户失败"); +// } +// } + + /** + * 测试根据ID修改一个用户的姓名 + */ +// @Test +// void updateOneTest() { +// // 定义用户实体 +// SysUser user = new SysUser(); +// // 随机填充数据 +// user.setId(10006); +// user.setUsername("李四"); +// // 执行修改 +// if (userService.updateById(user)) { +// System.out.println("修改用户信息成功"); +// } else { +// System.out.println("修改用户信息失败"); +// } +// } + + /** + * 测试根据ID查询一个用户的信息 + */ +// @Test +// void getOneTest() { +// SysUser user = userService.getById(100007); +// if (null != user) { +// System.out.println(user); +// } else { +// System.out.println("查无此用户"); +// } +// } + + /** + * 测试根据ID删除一个用户的信息 + */ + @Test + void logicDeleteTest() { + if (userService.removeById(10010)) { + System.out.println("删除成功"); + } else { + System.out.println("删除失败"); + } + } + +// /** +// * 分页查询测试 +// */ +// @Test +// void pageTest() { +// // 进行分页查询 +// Page userPage = userService.page(new Page<>(2, 2), null); +// // 获取查询的用户列表 +// List userList = userPage.getRecords(); +// System.out.println(userList); +// System.out.println("当前页:" + userPage.getCurrent()); +// System.out.println("当前页显示条数:" + userPage.getSize()); +// System.out.println("总数:" + userPage.getTotal()); +// } + +} diff --git a/ss-admin/src/test/java/com/zxdmy/excite/admin/utils/RedisUtilsTest.java b/ss-admin/src/test/java/com/zxdmy/excite/admin/utils/RedisUtilsTest.java new file mode 100644 index 0000000..78cd0a9 --- /dev/null +++ b/ss-admin/src/test/java/com/zxdmy/excite/admin/utils/RedisUtilsTest.java @@ -0,0 +1,103 @@ +package com.zxdmy.excite.admin.utils; + + +import com.zxdmy.excite.common.config.ExciteConfig; +import com.zxdmy.excite.common.service.RedisService; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.utils.AuthUtils; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + *

                          + * Redis使用测试类 + *

                          + * + * @author 沈松 + * @since 2021-09-30 0030 20:14 + */ +@SpringBootTest +class RedisUtilsTest { + + @Autowired + private RedisService redisUtils; + + @Autowired + private ExciteConfig exciteConfig; + + @Test + void MyConfigTest() { + System.out.println(exciteConfig.getRsaPrivateKey()); + } + + @Test + void testPrefixDelete(){ +// redisUtils.removeByPrefix("menu"); + AuthUtils.clearSystemMenuListCache(true); + } + @Test + void redisTest() { + // 写入Redis:普通测试 + redisUtils.set(UUID.randomUUID().toString(), UUID.randomUUID()); + // 写入redis:普通测试,带过期时间 + redisUtils.set(UUID.randomUUID().toString(), UUID.randomUUID(), 100L); + + // 写入Redis:永久的值 + redisUtils.set("10000", "这个值是永久的"); + // 写入Redis:有过期时间 + redisUtils.set("10001", "这个值是有过期时间的,过期时间120S", 120L); + + // 获取存在的值 + String name = (String) redisUtils.get("10000"); + System.out.println(name); // 输出:这个值是永久的 + // 获取不存在的值 + String name2 = (String) redisUtils.get("sdfdsfsdfsdfdsf"); + System.out.println(name2); //输出:null + + // 获取过期时间:永久 + Long time = redisUtils.getExpire("10000"); + System.out.println(time); // 输出:-1 + // 获取过期时间:定时 + Long time2 = redisUtils.getExpire("10001"); + System.out.println(time2); // 输出:(一个正数) + // 获取过期时间:不存在 + Long time3 = redisUtils.getExpire("534564564564"); + System.out.println(time3); // 输出:-2 + + // 测试存在 + if (redisUtils.hasKey("10001")) { + System.out.println("10001存在"); + } + // 测试不存在 + if (redisUtils.hasKey("11111")) { + System.out.println("11111存在"); + } else { + System.out.println("11111不存在"); // 输出:11111不存在 + } + + // 测试实体 + SysUser user = new SysUser(); + user.setId(10006); + user.setUsername("这是昵称"); + redisUtils.set("10006", user); + // 测试获取实体 + SysUser user2 = (SysUser) redisUtils.get("10006"); + System.out.println(user2.getUsername()); // 输出:这是昵称 + + // 测试列表 + System.out.println("测试保存列表"); + List userList = new ArrayList<>(); + userList.add(user); + userList.add(user); + redisUtils.set("userList", (Serializable) userList); + List userList2 = (List) redisUtils.get("userList"); + for (SysUser user1 : userList2) { + System.out.println(user1); + } + } +} diff --git a/ss-common/README.md b/ss-common/README.md new file mode 100644 index 0000000..6a056e4 --- /dev/null +++ b/ss-common/README.md @@ -0,0 +1,3 @@ +# Ss-Common模块 + +主要放常用的工具类 diff --git a/ss-common/pom.xml b/ss-common/pom.xml new file mode 100644 index 0000000..75bab73 --- /dev/null +++ b/ss-common/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + + + com.zxdmy.excite + shensong + 2.0.0 + + + ss-common + 2.0.0 + + ss-common + + 此模块主要继承公共的工具类。 + + + + + + + + + + + + + cn.dev33 + sa-token-dao-redis-jackson + 1.28.0 + + + + + org.apache.commons + commons-pool2 + + + + + com.github.penggle + kaptcha + 2.3.2 + + + + + diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/base/BaseController.java b/ss-common/src/main/java/com/zxdmy/excite/common/base/BaseController.java new file mode 100644 index 0000000..6561ba7 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/base/BaseController.java @@ -0,0 +1,208 @@ +package com.zxdmy.excite.common.base; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ModelAttribute; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + *

                          + * 通用的控制类 + *

                          + * + * @author 沈松 + * @since 2021-09-05 0005 22:58 + */ +public class BaseController { + + @Resource + protected HttpServletRequest request; + @Resource + protected HttpServletResponse response; + + @ModelAttribute + public void initReqAndRes(HttpServletRequest request, HttpServletResponse response) { + this.request = request; + this.response = response; + } + + /** + * 请求成功消息(JSON code:200;浏览器Status Code:200) + * 相关说明: + * --- JSON code:指的是返回的JSON数据中的code字段的值 + * --- Status Code:指的是前端按下F12后,浏览器控制台中请求相关API后,返回给浏览器的状态值。 + * 如果需要修改Status Code,则需要传入[org.springframework.http.HttpStatus]类中的各个参数,如:HttpStatus.OK.value()。 + * + * @param message 消息 + * @return 结果类 + */ + public BaseResult success(String message) { + response.setStatus(HttpStatus.OK.value()); + return new BaseResult(HttpStatus.OK.value(), message); + } + + /** + * 请求成功消息(JSON code:自定义;浏览器Status Code:200) + * + * @param code 状态码 + * @param message 消息 + * @return 结果类 + */ + public BaseResult success(int code, String message) { + response.setStatus(HttpStatus.OK.value()); + return new BaseResult(code, message); + } + + /** + * 请求成功实体(JSON code:200;浏览器Status Code:200) + * + * @param data 实体 + * @return 结果类 + */ + public BaseResult success(Object data) { + response.setStatus(HttpStatus.OK.value()); + return new BaseResult(HttpStatus.OK.value(), data); + } + + /** + * 请求成功实体(JSON code:自定义;浏览器Status Code:200) + * + * @param code 状态码 + * @param data 消息 + * @return 结果类 + */ + public BaseResult success(int code, Object data) { + response.setStatus(HttpStatus.OK.value()); + return new BaseResult(code, data); + } + + /** + * 请求成功消息(JSON code:自定义;浏览器Status Code:同返回码) + * + * @param httpStatus 状态码 + * @param message 消息 + * @return 结果类 + */ + public BaseResult success(HttpStatus httpStatus, String message) { + response.setStatus(httpStatus.value()); + return new BaseResult(httpStatus.value(), message); + } + + /** + * 请求成功消息+数据(JSON code:200;浏览器Status Code:200) + * + * @param message 消息 + * @param data 数据 + * @return 结果类 + */ + public BaseResult success(String message, Object data) { + response.setStatus(HttpStatus.OK.value()); + return new BaseResult(HttpStatus.OK.value(), message, data); + } + + /** + * 请求成功消息+数据(JSON code:自定义;浏览器Status Code:200) + * + * @param code 状态码 + * @param message 消息 + * @param data 数据 + * @return 结果类 + */ + public BaseResult success(int code, String message, Object data) { + response.setStatus(HttpStatus.OK.value()); + return new BaseResult(code, message, data); + } + + /** + * 请求成功消息+数据(JSON code:自定义;浏览器Status Code:同返回码) + * + * @param httpStatus 状态码 + * @param message 消息 + * @param data 数据 + * @return 结果类 + */ + public BaseResult success(HttpStatus httpStatus, String message, Object data) { + response.setStatus(httpStatus.value()); + return new BaseResult(httpStatus.value(), message, data); + } + + /** + * 请求成功消息+数据+总数,用于分页显示(JSON code:200;浏览器Status Code:200) + * + * @param message 消息 + * @param data 数据 + * @param count 记录数 + * @return 结果类 + */ + public BaseResult success(String message, Object data, int count) { + response.setStatus(HttpStatus.OK.value()); + return new BaseResult(HttpStatus.OK.value(), message, data).put("count", count); + } + + /** + * 请求成功消息+数据+总数,用于分页显示(JSON code:自定义;浏览器Status Code:200) + * + * @param code 状态码 + * @param message 消息 + * @param data 数据 + * @param count 记录数 + * @return 结果类 + */ + public BaseResult success(int code, String message, Object data, int count) { + response.setStatus(HttpStatus.OK.value()); + return new BaseResult(code, message, data).put("count", count); + } + + /** + * 请求成功消息+数据+总数,用于分页显示(JSON code:自定义;浏览器Status Code:同返回码) + * + * @param httpStatus 状态码 + * @param message 消息 + * @param data 数据 + * @param count 记录数 + * @return 结果类 + */ + public BaseResult success(HttpStatus httpStatus, String message, Object data, int count) { + response.setStatus(httpStatus.value()); + return new BaseResult(httpStatus.value(), message, data).put("count", count); + } + + + /** + * 请求失败消息(JSON code:400;浏览器Status Code:200) + * + * @param message 消息 + * @return 结果类 + */ + public BaseResult error(String message) { + response.setStatus(HttpStatus.OK.value()); + return new BaseResult(HttpStatus.BAD_REQUEST.value(), message); + } + + /** + * 请求失败消息(JSON code:自定义;浏览器Status Code:200) + * + * @param code 状态码 + * @param message 消息 + * @return 结果类 + */ + public BaseResult error(int code, String message) { + response.setStatus(HttpStatus.OK.value()); + return new BaseResult(code, message); + } + + /** + * 请求失败消息(JSON code:自定义;浏览器Status Code:同返回码) + * + * @param httpStatus 状态码 + * @param message 消息 + * @return 结果类 + */ + public BaseResult error(HttpStatus httpStatus, String message) { + response.setStatus(httpStatus.value()); + return new BaseResult(httpStatus.value(), message); + } + +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/base/BaseResult.java b/ss-common/src/main/java/com/zxdmy/excite/common/base/BaseResult.java new file mode 100644 index 0000000..0413603 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/base/BaseResult.java @@ -0,0 +1,104 @@ +package com.zxdmy.excite.common.base; + +import java.util.HashMap; + +/** + *

                          + * 通用的返回结果类 + *

                          + * + * @author 沈松 + * @since 2021-09-05 0005 23:01 + */ +public class BaseResult extends HashMap { + + private static final long serialVersionUID = 1L; + + /** + * 几个静态常量 + */ + private static final Integer MAX_SUCCESS_VALUE = 299; + private static final String SUCCESS = "success"; + private static final String CODE = "code"; + private static final String MSG = "msg"; + private static final String DATA = "data"; + private static final String COUNT = "count"; + private static final String PAGE = "page"; + private static final String SIZE = "size"; + + /** + * 初始化 BaseResult 对象,其消息为空。 + */ + public BaseResult() { + } + + /** + * 封装结果类,消息。 + * + * @param code 状态代码 + * @param msg 消息内容 + */ + public BaseResult(int code, String msg) { + if (code <= MAX_SUCCESS_VALUE) { + super.put(SUCCESS, true); + } else { + super.put(SUCCESS, false); + } + super.put(CODE, code); + super.put(MSG, msg); + } + + /** + * 封装结果类,实体。 + * + * @param code 状态代码 + * @param data 消息实体 + */ + public BaseResult(int code, Object data) { + if (code <= MAX_SUCCESS_VALUE) { + super.put(SUCCESS, true); + } else { + super.put(SUCCESS, false); + } + super.put(CODE, code); + if (null != data) { + super.put(DATA, data); + } + } + + + /** + * 封装结果类,消息+实体。 + * + * @param code 状态类型 + * @param msg 消息内容 + * @param data 数据对象 + */ + public BaseResult(int code, String msg, Object data) { + if (code <= MAX_SUCCESS_VALUE) { + super.put(SUCCESS, true); + } else { + super.put(SUCCESS, false); + } + super.put(CODE, code); + super.put(MSG, msg); + if (null != data) { + super.put(DATA, data); + } + } + + + /** + * 以上三类是默认的类型。如果还有其他参数要返回,使用.put(key,value)的链式调用方式追加。 + * + * @param key 键 + * @param value 值/任意数据对象 + * @return 链式调用 + */ + @Override + public BaseResult put(String key, Object value) { + super.put(key, value); + return this; + } + +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/base/ErrorController.java b/ss-common/src/main/java/com/zxdmy/excite/common/base/ErrorController.java new file mode 100644 index 0000000..f8562c6 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/base/ErrorController.java @@ -0,0 +1,43 @@ +package com.zxdmy.excite.common.base; + + +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * 全局请求错误返回结果控制类 + * + * @author 沈松 + * @since 2021-09-11 0011 23:27 + */ +@Controller +@AllArgsConstructor +@RequestMapping("/error") +public class ErrorController extends BaseController { + + /** + * 请求资源不存在返回结果 + * + * @return 错误信息 + */ + @GetMapping(value = "/404") + public String error404() { +// return error(HttpStatus.NOT_FOUND, "请求的资源不存在"); + return "error/404"; + } + + /** + * 服务器错误返回结果 + * + * @return 错误信息 + */ + @GetMapping(value = "/500") + @ResponseBody + public BaseResult error500() { + return error(HttpStatus.INTERNAL_SERVER_ERROR, "服务器内部错误:可能请求资源不存在"); + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/config/ErrorPageConfig.java b/ss-common/src/main/java/com/zxdmy/excite/common/config/ErrorPageConfig.java new file mode 100644 index 0000000..0052972 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/config/ErrorPageConfig.java @@ -0,0 +1,26 @@ +package com.zxdmy.excite.common.config; + +import org.springframework.boot.web.server.ErrorPage; +import org.springframework.boot.web.server.ErrorPageRegistrar; +import org.springframework.boot.web.server.ErrorPageRegistry; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * 全局错误访问返回结果 + * + * @author 沈松 + * @since 2021-09-08 0008 21:00 + */ +@Component +public class ErrorPageConfig implements ErrorPageRegistrar { + @Override + public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { + errorPageRegistry.addErrorPages( + // 当遇到 NOT_FOUND 错误时,请求 /error/404 路由。 + new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"), + // 当遇到 INTERNAL_SERVER_ERROR 错误时,请求 /error/500 路由。 + new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500") + ); + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/config/ExciteConfig.java b/ss-common/src/main/java/com/zxdmy/excite/common/config/ExciteConfig.java new file mode 100644 index 0000000..6a33346 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/config/ExciteConfig.java @@ -0,0 +1,67 @@ +package com.zxdmy.excite.common.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + *

                          + * 描述 + *

                          + * + * @author 沈松 + * @since 2021-10-07 0007 19:04 + */ +@Component +@ConfigurationProperties(prefix = "excite") +public class ExciteConfig { + + private String name; + + /** + * 是否允许Redis缓存:true:允许 | false:不允许 + * 此Redis缓存用到的地方主要有:用户角色、权限控制; + */ + private Boolean allowRedis; + + /** + * RSA加密算法的公钥 + */ + private String rsaPublicKey; + + /** + * RSA加密算法的私钥 + */ + private String rsaPrivateKey; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Boolean getAllowRedis() { + return allowRedis; + } + + public void setAllowRedis(Boolean allowRedis) { + this.allowRedis = allowRedis; + } + + public String getRsaPublicKey() { + return rsaPublicKey; + } + + public void setRsaPublicKey(String rsaPublicKey) { + this.rsaPublicKey = rsaPublicKey; + } + + public String getRsaPrivateKey() { + return rsaPrivateKey; + } + + public void setRsaPrivateKey(String rsaPrivateKey) { + this.rsaPrivateKey = rsaPrivateKey; + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/config/KaptchaConfig.java b/ss-common/src/main/java/com/zxdmy/excite/common/config/KaptchaConfig.java new file mode 100644 index 0000000..fc81e0d --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/config/KaptchaConfig.java @@ -0,0 +1,139 @@ +package com.zxdmy.excite.common.config; + +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; + +import static com.google.code.kaptcha.Constants.*; + +/** + *

                          + * Google验证码配置类 + *

                          + * + * @author 沈松 + * @since 2021-10-04 0004 20:12 + */ +@Configuration +public class KaptchaConfig { + + /** + * 验证码配置默认配置 + * + * @return 配置信息 + */ + @Bean(name = "captchaProducer") + public DefaultKaptcha getKaptchaBean() { + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + // 是否有边框 默认为true 我们可以自己设置yes,no + properties.setProperty(KAPTCHA_BORDER, "yes"); + // 验证码文本字符颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); + // 验证码图片宽度 默认为200 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); + // 验证码图片高度 默认为50 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); + // 验证码文本字符大小 默认为40 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38"); + // KAPTCHA_SESSION_KEY + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode"); + // 验证码文本字符长度 默认为5 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4"); + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); + Config config = new Config(properties); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } + + /** + * 验证码数学题类配置(一位数加减乘除) + * + * @return 配置信息 + */ + @Bean(name = "captchaProducerMathOne") + public DefaultKaptcha getKaptchaBeanMathOne() { + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + // 是否有边框 默认为true 我们可以自己设置yes,no + properties.setProperty(KAPTCHA_BORDER, "yes"); + // 边框颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); + // 验证码文本字符颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); + // 验证码图片宽度 默认为200 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); + // 验证码图片高度 默认为50 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); + // 验证码文本字符大小 默认为40 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); + // KAPTCHA_SESSION_KEY + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); + // 验证码文本生成器 + properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.zxdmy.excite.common.utils.KaptchaMathOneTextCreator"); + // 验证码文本字符间距 默认为2 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); + // 验证码文本字符长度 默认为 5 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); + // 验证码噪点颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); + // 干扰实现类 + properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise"); + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); + Config config = new Config(properties); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } + + /** + * 验证码数学题类配置(两位数的加减乘除) + * + * @return 配置信息 + */ + @Bean(name = "captchaProducerMathTwo") + public DefaultKaptcha getKaptchaBeanMathTwo() { + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + Properties properties = new Properties(); + // 是否有边框 默认为true 我们可以自己设置yes,no + properties.setProperty(KAPTCHA_BORDER, "yes"); + // 边框颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90"); + // 验证码文本字符颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue"); + // 验证码图片宽度 默认为200 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160"); + // 验证码图片高度 默认为50 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60"); + // 验证码文本字符大小 默认为40 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35"); + // KAPTCHA_SESSION_KEY + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath"); + // 验证码文本生成器 + properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.zxdmy.excite.common.utils.KaptchaMathTwoTextCreator"); + // 验证码文本字符间距 默认为2 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3"); + // 验证码文本字符长度 默认为5 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6"); + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier"); + // 验证码噪点颜色 默认为Color.BLACK + properties.setProperty(KAPTCHA_NOISE_COLOR, "white"); + // 干扰实现类 + properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise"); + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy"); + Config config = new Config(properties); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } + +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/config/MybatisPlusConfig.java b/ss-common/src/main/java/com/zxdmy/excite/common/config/MybatisPlusConfig.java new file mode 100644 index 0000000..56b0117 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/config/MybatisPlusConfig.java @@ -0,0 +1,34 @@ +package com.zxdmy.excite.common.config; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + *

                          + * Mybatis Plus 配置信息 + *

                          + * + * @author 沈松 + * @since 2021-09-01 0001 18:34 + */ +@Configuration +@MapperScan({"com.zxdmy.excite.system.mapper", ""}) +public class MybatisPlusConfig { + + /** + * 分页插件配置 + * + * @return MP拦截器 + */ + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; + } + +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/config/RedisConfig.java b/ss-common/src/main/java/com/zxdmy/excite/common/config/RedisConfig.java new file mode 100644 index 0000000..12e550c --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/config/RedisConfig.java @@ -0,0 +1,100 @@ +package com.zxdmy.excite.common.config; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.stereotype.Component; + +import java.io.Serializable; + +/** + *

                          + * Redis 相关配置,参考自:spring-boot-demo + *

                          + * + * @author 沈松 + * @since 2021-09-30 0030 19:15 + */ +@Component +@Configuration +@EnableCaching +@AutoConfigureAfter(RedisAutoConfiguration.class) +@ConfigurationProperties(prefix = "spring.redis") +public class RedisConfig { + + /** + * 自定义属性:Redis key 的前缀 + */ + private String prefix = "redis:prefix:"; + + /** + * 自定义属性:是否开启Redis自定义前缀,默认关闭。 + */ + private Boolean allowPrefix = false; + + /** + * 默认情况下的模板只能支持RedisTemplate,也就是只能存入字符串,因此支持序列化 + */ + @Bean + public RedisTemplate redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + // key采用String的序列化方式 + template.setKeySerializer(new StringRedisSerializer()); + // hash的key也采用String的序列化方式 + template.setHashKeySerializer(new StringRedisSerializer()); + // value序列化方式采用jackson + template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); + // hash的value序列化方式采用jackson + template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); + template.setConnectionFactory(redisConnectionFactory); + return template; + } + + /** + * 配置使用注解的时候缓存配置,默认是序列化反序列化的形式,加上此配置则为 json 形式 + */ + @Bean + public CacheManager cacheManager(RedisConnectionFactory factory) { + // 配置序列化 + RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); + RedisCacheConfiguration redisCacheConfiguration = config + // 覆盖默认的构造key,否则会多出一个冒号 + .computePrefixWith(cacheName -> this.allowPrefix ? this.prefix + cacheName + ":" : cacheName) + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) + // 不缓存空值 + // .disableCachingNullValues() + ; + + return RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build(); + } + + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public Boolean getAllowPrefix() { + return allowPrefix; + } + + public void setAllowPrefix(Boolean allowPrefix) { + this.allowPrefix = allowPrefix; + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/config/SpringDocConfig.java b/ss-common/src/main/java/com/zxdmy/excite/common/config/SpringDocConfig.java new file mode 100644 index 0000000..8f9894a --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/config/SpringDocConfig.java @@ -0,0 +1,59 @@ +package com.zxdmy.excite.common.config; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + *

                          + * SpringDoc API配置文档 + *

                          + * + * @author 沈松 + * @since 2021-09-10 0010 21:57 + */ +// 全局只能定义一个,主要配置文档信息和安全配置 +@OpenAPIDefinition( + // 配置接口文档基本信息,用于网页显示 + info = @Info( + title = "ExciteCMS", //标题 + version = "1.0", //版本号 + description = "An integrated content management system based on Spring Boot (v2.5.4)" //描述信息 + ) + // 当然还可以添加其他的安全配置。 +) +@Configuration // 如果需要在此处配置分组信息,则需要添加此注解。 +public class SpringDocConfig { + + @Bean + public GroupedOpenApi guestApi() { + return GroupedOpenApi.builder() + // 分组名 + .group("guest") + // 扫描的包路径。可选项。 + .packagesToScan("com.zxdmy.cms.excite.guest") + // 匹配的路径。可选项,可以与包路径二选一,也可以都用。 + .pathsToMatch("/guest/**") + .build(); + } + +// @Bean +// public GroupedOpenApi thirdApi() { +// return GroupedOpenApi.builder() +// // 分组名 +// .group("third") +// // 扫描的包路径。可选项。 +// .packagesToScan("com.zxdmy.cms.excite.third") +// // 匹配的路径。可选项,可以与包路径二选一,也可以都用。 +// .pathsToMatch("/third/**") +// .build(); +// } + +} + + + + + diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/entity/CaptchaDomain.java b/ss-common/src/main/java/com/zxdmy/excite/common/entity/CaptchaDomain.java new file mode 100644 index 0000000..642ff36 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/entity/CaptchaDomain.java @@ -0,0 +1,51 @@ +package com.zxdmy.excite.common.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.awt.image.BufferedImage; +import java.io.Serializable; + +/** + *

                          + * 第三方验证码实体类 + *

                          + * + * @author 沈松 + * @since 2021-10-04 0004 20:02 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class CaptchaDomain implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 验证码的Token + */ + private String token; + + /** + * 验证码的字符。返回的JSON,禁止返回给前端。 + */ + @JsonIgnore + private String text; + + /** + * 验证码的验证字符。比如算式的结果等。 + */ + @JsonIgnore + private String code; + + /** + * 验证码缓冲图像 + */ + @JsonIgnore + private BufferedImage image; + + /** + * 验证码图片的Base64字符串 + */ + private String base64; +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/entity/GlobalConfig.java b/ss-common/src/main/java/com/zxdmy/excite/common/entity/GlobalConfig.java new file mode 100644 index 0000000..90be790 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/entity/GlobalConfig.java @@ -0,0 +1,68 @@ +package com.zxdmy.excite.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.time.LocalDateTime; +import java.io.Serializable; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 组件配置信息表 + *

                          + * + * @author 沈松 + * @since 2022-01-03 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class GlobalConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键,自增 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 配置信息的服务:如qiniu,aliyun + */ + private String confService; + + /** + * 配置信息的主键:如qiniu、alipay等等 + */ + private String confKey; + + /** + * 配置信息的JSON值 + */ + private String confValue; + + /** + * 是否加密:1-是 0-否 + */ + private Integer encrypt; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 删除时间 + */ + private LocalDateTime deleteTime; + + +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/entity/PageList.java b/ss-common/src/main/java/com/zxdmy/excite/common/entity/PageList.java new file mode 100644 index 0000000..6a65cdc --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/entity/PageList.java @@ -0,0 +1,56 @@ +package com.zxdmy.excite.common.entity; + +import java.util.ArrayList; +import java.util.List; + +public class PageList { + private int page;//当前页数 + private int total;//总的页数 + private int count;//总的记录数 + private ArrayList list;//当前页数据 + + /** + * @param list 当前页数据 + * @param page 当前页数 + * @param size 每页数据量 + * @param count 总的记录数量 + */ + public PageList(ArrayList list, int page, int size, int count) { + this.page = page; + this.count = count; + this.list = list; + this.total = count % size == 0 ? count / size : (count / size) + 1; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public int getPage() { + return page; + } + + public void setPage(int page) { + this.page = page; + } + + public int getTotal() { + return total; + } + + public void setTotal(int total) { + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(ArrayList list) { + this.list = list; + } +} \ No newline at end of file diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/enums/CloudCode.java b/ss-common/src/main/java/com/zxdmy/excite/common/enums/CloudCode.java new file mode 100644 index 0000000..5c7596e --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/enums/CloudCode.java @@ -0,0 +1,25 @@ +package com.zxdmy.excite.common.enums; + +public enum CloudCode { + + FOLDER_IMAGE("https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/cloud/folder.jpg", "目录图标"), + PDF_IMAGE("https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/cloud/file.png", "PDF"), + FOLDER_NAME("文件夹", "目录格式"); + + private final String code; + + private final String desc; + + CloudCode(String code, String desc) { + this.code = code; + this.desc = desc; + } + + public String getCode() { + return this.code; + } + + public String getDesc() { + return this.desc; + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/enums/ReturnCode.java b/ss-common/src/main/java/com/zxdmy/excite/common/enums/ReturnCode.java new file mode 100644 index 0000000..5ed97f6 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/enums/ReturnCode.java @@ -0,0 +1,70 @@ +package com.zxdmy.excite.common.enums; + +/** + *

                          + * 通用的返回结果返回码枚举类 + *

                          + * + * @author 沈松 + * @since 2021-09-05 0005 23:59 + */ +public enum ReturnCode { + + // 以下是常用的HTTP状态码 + /** + * 客户端请求成功。状态码:200 + */ + OK(200, "OK"), + /** + * 客户端请求已创建。状态码:201 + */ + CREATED(201, "Created"), + /** + * 客户端请求已接受。状态码:202 + */ + ACCEPTED(202, "Accepted"), + + /** + * 请求错误。状态码:400 + */ + BAD_REQUEST(400, "Bad Request"), + /** + * 拒绝访问。状态码:401 + */ + UNAUTHORIZED(401, "Unauthorized"), + /** + * 禁止访问。状态码:403 + */ + FORBIDDEN(403, "Forbidden"), + /** + * 请求不存在。状态码:404 + */ + NOT_FOUND(404, "Not Found"), + /** + * 方法不被允许。状态码:405 + */ + METHOD_NOT_ALLOWED(405, "Method Not Allowed"), + + // 当然还可以添加自定义的其他返回码。 + INVALID_ID(40001, "不合法的ID"), + INVALID_FILE_TYPE(40002, "不合法的文件类型"), + INVALID_FILE_SIZE(40003, "不合法的文件大小"), + INVALID_URL(40004, "不合法的链接"); + + private final int code; + + private final String reason; + + ReturnCode(int code, String reason) { + this.code = code; + this.reason = reason; + } + + public int getCode() { + return this.code; + } + + public String getReason() { + return this.reason; + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/enums/SystemCode.java b/ss-common/src/main/java/com/zxdmy/excite/common/enums/SystemCode.java new file mode 100644 index 0000000..f04f6e8 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/enums/SystemCode.java @@ -0,0 +1,73 @@ +package com.zxdmy.excite.common.enums; + +public enum SystemCode { + + /** + * 系统菜单默认顺序:0 + */ + MENU_DEFAULT_SORT(50, "菜单默认排序"), + /** + * 默认顺序:50 + */ + SORT_DEFAULT(50, "默认排序"), + + FOLDER_Y(0, "是文件夹"), + + FOLDER_N(1, "是文件"), + /** + * 记录状态:正常,值:1 + */ + STATUS_Y(1, "记录状态正常"), + /** + * 记录状态:异常,值:0 + */ + STATUS_N(0, "记录状态封禁"), + /** + * 记录状态:正常锁定,值:2 + */ + STATUS_Y_BLOCK(2, "状态正常,并且无法编辑状态"), + + /** + * 记录可以编辑:1 + */ + EDITABLE_Y(1, "记录可以编辑"), + /** + * 记录禁止编辑:0 + */ + EDITABLE_N(0, "记录禁止编辑"), + + /** + * 记录可以删除:1 + */ + REMOVABLE_Y(1, "记录可以删除"), + /** + * 记录禁止删除:0 + */ + REMOVABLE_N(0, "记录禁止删除"), + /** + * 是否删除:是 - 0 + */ + DELETE_Y(1, "已删除"), + /** + * 是否删除:否 - 0 + */ + DELETE_N(0, "未删除"); + + + private final int code; + + private final String desc; + + SystemCode(int code, String desc) { + this.code = code; + this.desc = desc; + } + + public int getCode() { + return this.code; + } + + public String getDesc() { + return this.desc; + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/exception/GlobalException.java b/ss-common/src/main/java/com/zxdmy/excite/common/exception/GlobalException.java new file mode 100644 index 0000000..7919e7e --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/exception/GlobalException.java @@ -0,0 +1,85 @@ +package com.zxdmy.excite.common.exception; + +import cn.dev33.satoken.exception.DisableLoginException; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.exception.NotPermissionException; +import cn.dev33.satoken.exception.NotRoleException; +import com.zxdmy.excite.common.base.BaseController; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + *

                          + * 全局异常处理 + *

                          + * + * @author 沈松 + * @since 2021-10-12 0012 20:57 + */ +@ControllerAdvice +public class GlobalException extends BaseController { + + @ResponseBody + @ExceptionHandler + public Object handlerException(Exception e, HttpServletRequest request, HttpServletResponse response) throws Exception { + // 打印堆栈,以供调试 + System.out.println("==============全局异常=============="); + e.printStackTrace(); + // 不同异常返回不同状态码 + + String result = "系统错误,请重试!"; + // 如果是未登录异常 + if (e instanceof NotLoginException) { + NotLoginException ee = (NotLoginException) e; + result = "用户未登录"; + // 前后端同域,所以未登录就直接跳转至登录页面 + response.sendRedirect(request.getContextPath() + "/system/login"); + } + // 如果是角色异常 + else if (e instanceof NotRoleException) { + NotRoleException ee = (NotRoleException) e; + result = "无此角色:" + ee.getRole(); + } + // 如果是权限异常 + else if (e instanceof NotPermissionException) { + NotPermissionException ee = (NotPermissionException) e; + result = "无此权限:" + ee.getCode(); + } + // 如果是被封禁异常 + else if (e instanceof DisableLoginException) { + DisableLoginException ee = (DisableLoginException) e; + result = "账号被封禁:" + ee.getDisableTime() + "秒后解封"; + } + // 不支持的请求 + else if (e instanceof HttpRequestMethodNotSupportedException) { + return "请求不支持"; + } + // 信息校验失败提示 + else if (e instanceof BindException) { + BindingResult bindingResult = ((BindException) e).getBindingResult(); + StringBuilder errMsg = new StringBuilder(); + if (bindingResult.hasErrors()) { + Integer i = 1; + for (FieldError fieldError : bindingResult.getFieldErrors()) { + errMsg.append(i).append(". ").append(fieldError.getDefaultMessage()).append("!"); + i++; + } + } + result = errMsg.toString(); + } + // 其他异常, 输出:500 + 异常信息 + else { + result = e.getMessage(); + } + // 返回给前端 + return error(500, result); + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/exception/ServiceException.java b/ss-common/src/main/java/com/zxdmy/excite/common/exception/ServiceException.java new file mode 100644 index 0000000..55e0b90 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/exception/ServiceException.java @@ -0,0 +1,47 @@ +package com.zxdmy.excite.common.exception; + +/** + *

                          + * 服务层异常处理,继承RunTimeException,来保证对异常进行事务回滚 + *

                          + * + * @author 沈松 + * @since 2021-09-23 0023 19:54 + */ +public class ServiceException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private String message; + + private String details; + + public ServiceException() { + } + + public ServiceException(String message) { + this.message = message; + } + + public ServiceException(String message, String details) { + this.message = message; + this.details = details; + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getDetails() { + return details; + } + + public void setDetails(String details) { + this.details = details; + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/mapper/GlobalConfigMapper.java b/ss-common/src/main/java/com/zxdmy/excite/common/mapper/GlobalConfigMapper.java new file mode 100644 index 0000000..0183770 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/mapper/GlobalConfigMapper.java @@ -0,0 +1,16 @@ +package com.zxdmy.excite.common.mapper; + +import com.zxdmy.excite.common.entity.GlobalConfig; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

                          + * 组件配置信息表 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2022-01-03 + */ +public interface GlobalConfigMapper extends BaseMapper { + +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/service/CaptchaService.java b/ss-common/src/main/java/com/zxdmy/excite/common/service/CaptchaService.java new file mode 100644 index 0000000..c9e4e65 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/service/CaptchaService.java @@ -0,0 +1,128 @@ +package com.zxdmy.excite.common.service; + +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.CaptchaUtil; +import com.google.code.kaptcha.Producer; + +import com.zxdmy.excite.common.entity.CaptchaDomain; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; +import sun.misc.BASE64Encoder; + +import javax.annotation.Resource; +import javax.imageio.ImageIO; +import java.io.ByteArrayOutputStream; +import java.security.SecureRandom; +import java.util.Random; +import java.util.UUID; + +/** + *

                          + * 验证码服务接口的实现 + *

                          + * + * @author 沈松 + * @since 2021-10-15 0015 10:18 + */ +@Service +@AllArgsConstructor +public class CaptchaService { + + @Resource(name = "captchaProducer") + private Producer captchaProducer; + + @Resource(name = "captchaProducerMathOne") + private Producer captchaProducerMathOne; + + @Resource(name = "captchaProducerMathTwo") + private Producer captchaProducerMathTwo; + + private static final String TYPE_CHAR = "char"; + private static final String TYPE_MATH_ONE = "math"; + private static final String TYPE_MATH_TWO = "math2"; + + /** + * Kaptcha生成验证码实体 + * + * @param type 类型,char - 字符(缺省) | math - 一位数算式 | math2 - 两位数算式 + * @return 验证码实体 + */ + public CaptchaDomain createGoogleCaptcha(String type) { + // 定义验证码实体 + CaptchaDomain captchaDomain = new CaptchaDomain(); + // 一位数加减乘除 + if (TYPE_MATH_ONE.equals(type)) { + // 生成文本 + String producerText = captchaProducerMathOne.createText(); + // 设置验证码字符 + captchaDomain.setText(producerText.substring(0, producerText.indexOf("@"))); + // 设置验证码答案码 + captchaDomain.setCode(producerText.substring(producerText.indexOf("@") + 1)); + // 设置验证码图片 + captchaDomain.setImage(captchaProducerMathOne.createImage(captchaDomain.getText())); + } + // 两位数加减乘除 + else if (TYPE_MATH_TWO.equals(type)) { + String producerText = captchaProducerMathTwo.createText(); + captchaDomain.setText(producerText.substring(0, producerText.indexOf("@"))); + captchaDomain.setCode(producerText.substring(producerText.indexOf("@") + 1)); + captchaDomain.setImage(captchaProducerMathTwo.createImage(captchaDomain.getText())); + } + // 缺省情况:字符 + else { + captchaDomain.setText(captchaProducer.createText()); + captchaDomain.setCode(captchaDomain.getText()); + captchaDomain.setImage(captchaProducer.createImage(captchaDomain.getText())); + } + // 生成base64 + try { + // 定义字节数组输出流 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + // 将图像以 jpg 的形式,写到字节数组输出流中 + ImageIO.write(captchaDomain.getImage(), "jpg", outputStream); + // 对字节数组Base64编码 + BASE64Encoder encoder = new BASE64Encoder(); + // 写入base64格式 + captchaDomain.setBase64("data:image/jpg;base64," + encoder.encode(outputStream.toByteArray())); + // 写入唯一Token + captchaDomain.setToken(UUID.randomUUID().toString()); + // 返回结果 + return captchaDomain; + } catch (Exception e) { + System.out.println(e.getMessage()); + return null; + } + } + + public CaptchaDomain createHutoolCaptcha(Integer width, Integer height) { + CaptchaDomain captchaDomain = new CaptchaDomain(); + // 生成 0、1、2 三个整数其一,随机对应下面的三种验证码类型 + // 注意:这里只是尽可能多的展示每种验证码的使用方法,实际项目中选择一种即可。 + Random random = new SecureRandom(); + int type = random.nextInt(3); + AbstractCaptcha captcha = null; + // 【0】生成 线段干扰验证码 + if (type == 0) { + //定义图形验证码的长和宽 + captcha = CaptchaUtil.createLineCaptcha(width, height); + } + // 【1】生成 圆圈干扰验证码 + else if (type == 1) { + //定义图形验证码的长、宽。还可以设置两个参数:验证码字符数、干扰元素个数 + captcha = CaptchaUtil.createCircleCaptcha(width, height); + } + // 【2】生成 扭曲干扰验证码 + else { + captcha = CaptchaUtil.createShearCaptcha(width, height); + } + // 信息配置 + captchaDomain.setText(captcha.getCode()); + captchaDomain.setCode(captcha.getCode()); + captchaDomain.setBase64(captcha.getImageBase64Data()); + captchaDomain.setImage(captcha.getImage()); + captchaDomain.setToken(UUID.randomUUID().toString()); + + return captchaDomain; + } + +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/service/IGlobalConfigService.java b/ss-common/src/main/java/com/zxdmy/excite/common/service/IGlobalConfigService.java new file mode 100644 index 0000000..d537dd0 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/service/IGlobalConfigService.java @@ -0,0 +1,24 @@ +package com.zxdmy.excite.common.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.zxdmy.excite.common.entity.GlobalConfig; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + *

                          + * 组件配置信息表 服务类 + *

                          + * + * @author 沈松 + * @since 2022-01-03 + */ +public interface IGlobalConfigService extends IService { + + boolean save(String confService, String confKey, Object object, boolean encrypt) throws JsonProcessingException; + + Object get(String confService, String confKey, Object object); + + List getList(String confService, Object object); +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/service/RedisService.java b/ss-common/src/main/java/com/zxdmy/excite/common/service/RedisService.java new file mode 100644 index 0000000..176c156 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/service/RedisService.java @@ -0,0 +1,176 @@ +package com.zxdmy.excite.common.service; + + +import com.zxdmy.excite.common.config.RedisConfig; +import lombok.AllArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.io.Serializable; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + *

                          + * Redis工具类 + *

                          + * + * @author 沈松 + * @since 2021-09-30 0030 19:15 + */ +@Service +@AllArgsConstructor +public class RedisService { + + private RedisTemplate redisTemplate; + + private RedisConfig redisConfig; + + /** + * 写入普通缓存,key由系统生成 + * + * @param value 值 + * @return 键 + */ + public String set(Serializable value) { + // 随机生成key + String key = UUID.randomUUID().toString(); + // 如果当前生成的key已经存在,重新生成 + if (hasKey(key)) { + return set(value); + } else { + // 写入缓存 + redisTemplate.opsForValue().set(redisConfig.getAllowPrefix() ? redisConfig.getPrefix() + key : key, value); + // 返回key + return key; + } + } + + /** + * 写入带过期时间的缓存,其中key由系统生成 + * + * @param value 值 + * @param expireTime 过期时间 + * @return 键key + */ + public String set(Serializable value, Long expireTime) { + // 随机生成key + String key = UUID.randomUUID().toString(); + // 如果当前随机生成的key已经存在,则重新生成 + if (hasKey(key)) { + return set(value, expireTime); + } else { + // 写入缓存 + redisTemplate.opsForValue().set(redisConfig.getAllowPrefix() ? redisConfig.getPrefix() + key : key, value, expireTime, TimeUnit.SECONDS); + // 返回key + return key; + } + } + + /** + * 写入普通缓存,指定key + * + * @param key 键 + * @param value 值 + * @return 结果 + */ + public boolean set(String key, Serializable value) { + boolean result = false; + try { + redisTemplate.opsForValue().set(redisConfig.getAllowPrefix() ? redisConfig.getPrefix() + key : key, value); + result = true; + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + /** + * 写入带过期时间的缓存,指定key + * + * @param key 键 + * @param value 值 + * @param expireTime 过期时间 + * @return 结果 + */ + public boolean set(String key, Serializable value, Long expireTime) { + boolean result = false; + try { + redisTemplate.opsForValue().set(redisConfig.getAllowPrefix() ? redisConfig.getPrefix() + key : key, value, expireTime, TimeUnit.SECONDS); + result = true; + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + /** + * 判断某个键是否存在 + * + * @param key 键 + * @return 存在与否 + */ + public boolean hasKey(String key) { + return Boolean.TRUE.equals(redisTemplate.hasKey(redisConfig.getAllowPrefix() ? redisConfig.getPrefix() + key : key)); + } + + /** + * 通过键获取值 + * + * @param key 缓存的键 + * @return 存在:值 | 不存在:null + */ + public Serializable get(String key) { + if (hasKey(key)) { + return redisTemplate.opsForValue().get(redisConfig.getAllowPrefix() ? redisConfig.getPrefix() + key : key); + } + return null; + } + + /** + * 获取某个键值的过期时间 + * + * @param key 键 + * @return 过期时间(秒),-1表示永久有效,-2表示不存在 + */ + public Long getExpire(String key) { + return redisTemplate.getExpire(redisConfig.getAllowPrefix() ? redisConfig.getPrefix() + key : key, TimeUnit.SECONDS); + } + + /** + * 通过键移出某个值 + * + * @param key 键 + */ + public void remove(String key) { + if (hasKey(key)) { + redisTemplate.delete(redisConfig.getAllowPrefix() ? redisConfig.getPrefix() + key : key); + } + } + + /** + * 删除包含指定前缀的值 + * + * @param prefix 键 + */ + public void removeByPrefix(String prefix) { + Set keys = redisTemplate.keys((redisConfig.getAllowPrefix() ? redisConfig.getPrefix() + prefix : prefix) + "*"); + if (null != keys && !keys.isEmpty()) { + redisTemplate.delete(keys); + } + } + + + /** + * 通过键移出某些值 + * + * @param keys 批量的键,示例:remove("001","002","003") + */ + public void remove(String... keys) { + for (String key : keys) { + remove(redisConfig.getAllowPrefix() ? redisConfig.getPrefix() + key : key); + } + + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/service/impl/GlobalConfigServiceImpl.java b/ss-common/src/main/java/com/zxdmy/excite/common/service/impl/GlobalConfigServiceImpl.java new file mode 100644 index 0000000..479a845 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/service/impl/GlobalConfigServiceImpl.java @@ -0,0 +1,149 @@ +package com.zxdmy.excite.common.service.impl; + +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.zxdmy.excite.common.config.ExciteConfig; +import com.zxdmy.excite.common.entity.GlobalConfig; +import com.zxdmy.excite.common.mapper.GlobalConfigMapper; +import com.zxdmy.excite.common.service.IGlobalConfigService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 组件配置信息表 服务实现类 + *

                          + * + * @author 沈松 + * @since 2022-01-03 + */ +@Service +@AllArgsConstructor +public class GlobalConfigServiceImpl extends ServiceImpl implements IGlobalConfigService { + + ObjectMapper objectMapper; + + ExciteConfig exciteConfig; + + /** + * 将配置信息保存/更新至数据库 + * + * @param confService 配置服务名 + * @param confKey 配置信息主键 + * @param object 实体类 + * @param encrypt 是否对value开启加密 + * @return 结果 + */ + @Override + public boolean save(String confService, String confKey, Object object, boolean encrypt) { + // 全局配置信息类 + GlobalConfig globalConfig = new GlobalConfig(); + globalConfig.setConfService(confService); + globalConfig.setConfKey(confKey); + // 实体类转JSON格式字符串 + String confValue; + try { + confValue = objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + System.out.println(e.getMessage()); + return false; + } + // 如果开启加密,则对confValue:使用公钥加密 + if (encrypt) { + RSA rsa = new RSA(null, exciteConfig.getRsaPublicKey()); + confValue = rsa.encryptBase64(confValue, KeyType.PublicKey); + globalConfig.setEncrypt(1); + } else { + globalConfig.setEncrypt(0); + } + globalConfig.setConfValue(confValue); + globalConfig.setUpdateTime(LocalDateTime.now()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("conf_service", confService).eq("conf_key", confKey); + return this.saveOrUpdate(globalConfig, queryWrapper); + } + + /** + * 从数据库中读取一条配置信息 + * + * @param confService 配置信息服务名 + * @param confKey 配置信息的key + * @param object 配置信息实体 + * @return 配置信息实体 + */ + @Override + public Object get(String confService, String confKey, Object object) { + // 根据要求查询指定【模块】和【key】的【value】 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("conf_service", confService).eq("conf_key", confKey); + GlobalConfig globalConfig = this.getOne(queryWrapper); + String confValue = globalConfig.getConfValue(); + // 为空:返回null + if (null == confValue || "".equals(confValue)) { + return null; + } + // 如果开启了加密:使用私钥进行解密 + if (1 == globalConfig.getEncrypt()) { + RSA rsa = new RSA(exciteConfig.getRsaPrivateKey(), null); + confValue = rsa.decryptStr(confValue, KeyType.PrivateKey); + } + // 尝试转换成指定类型 + try { + object = objectMapper.readValue(confValue, object.getClass()); + } catch (IOException e) { + // 转换出错:报错并返回空 + System.out.println(e.getMessage()); + return null; + } + // 返回转换后的结果 + return object; + } + + /** + * 根据服务的名字,获取其所有的配置信息 + * + * @param confService 服务名称 + * @param object 类别 + * @return 结果List + */ + @Override + public List getList(String confService, Object object) { + // 根据要求查询指定【服务模块】的【value】 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("conf_service", confService); + List globalConfigList = this.list(queryWrapper); + if (globalConfigList.size() == 0) { + return null; + } + List objectList = new ArrayList<>(); + for (GlobalConfig globalConfig : globalConfigList) { + String confValue = globalConfig.getConfValue(); + // 为空:继续下一个 + if (null == confValue || "".equals(confValue)) { + continue; + } + // 如果开启了加密:使用私钥进行解密 + if (1 == globalConfig.getEncrypt()) { + RSA rsa = new RSA(exciteConfig.getRsaPrivateKey(), null); + confValue = rsa.decryptStr(confValue, KeyType.PrivateKey); + } + // 尝试转换成指定类型 + try { + objectList.add(objectMapper.readValue(confValue, object.getClass())); + } catch (IOException e) { + // 转换出错:报错并返回空 + System.out.println(e.getMessage()); + } + } + return objectList; + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/utils/ArithUtils.java b/ss-common/src/main/java/com/zxdmy/excite/common/utils/ArithUtils.java new file mode 100644 index 0000000..a3f5e85 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/utils/ArithUtils.java @@ -0,0 +1,114 @@ +package com.zxdmy.excite.common.utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * 精确的浮点数运算工具类 + * + * @author 沈松 + * @since 2022/1/22 21:30 + */ +public class ArithUtils { + + /** + * 默认除法运算精度 + */ + private static final int DEF_DIV_SCALE = 10; + + /** + * 这个类不能实例化 + */ + private ArithUtils() { + } + + /** + * 提供精确的加法运算。 + * + * @param v1 被加数 + * @param v2 加数 + * @return 两个参数的和 + */ + public static double add(double v1, double v2) { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.add(b2).doubleValue(); + } + + /** + * 提供精确的减法运算。 + * + * @param v1 被减数 + * @param v2 减数 + * @return 两个参数的差 + */ + public static double sub(double v1, double v2) { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.subtract(b2).doubleValue(); + } + + /** + * 提供精确的乘法运算。 + * + * @param v1 被乘数 + * @param v2 乘数 + * @return 两个参数的积 + */ + public static double mul(double v1, double v2) { + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + return b1.multiply(b2).doubleValue(); + } + + /** + * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 + * 小数点以后10位,以后的数字四舍五入。 + * + * @param v1 被除数 + * @param v2 除数 + * @return 两个参数的商 + */ + public static double div(double v1, double v2) { + return div(v1, v2, DEF_DIV_SCALE); + } + + /** + * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 + * 定精度,以后的数字四舍五入。 + * + * @param v1 被除数 + * @param v2 除数 + * @param scale 表示表示需要精确到小数点以后几位。 + * @return 两个参数的商 + */ + public static double div(double v1, double v2, int scale) { + if (scale < 0) { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b1 = new BigDecimal(Double.toString(v1)); + BigDecimal b2 = new BigDecimal(Double.toString(v2)); + if (b1.compareTo(BigDecimal.ZERO) == 0) { + return BigDecimal.ZERO.doubleValue(); + } + return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); + } + + /** + * 提供精确的小数位四舍五入处理。 + * + * @param v 需要四舍五入的数字 + * @param scale 小数点后保留几位 + * @return 四舍五入后的结果 + */ + public static double round(double v, int scale) { + if (scale < 0) { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b = new BigDecimal(Double.toString(v)); + BigDecimal one = BigDecimal.ONE; + return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/utils/DateUtils.java b/ss-common/src/main/java/com/zxdmy/excite/common/utils/DateUtils.java new file mode 100644 index 0000000..0642fbe --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/utils/DateUtils.java @@ -0,0 +1,144 @@ +package com.zxdmy.excite.common.utils; + +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.lang.management.ManagementFactory; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 时间工具类 + * + * @author 沈松 + * @since 2022/1/22 21:31 + */ +public class DateUtils extends org.apache.commons.lang3.time.DateUtils { + + public static String YYYY = "yyyy"; + + public static String YYYY_MM = "yyyy-MM"; + + public static String YYYY_MM_DD = "yyyy-MM-dd"; + + public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; + + public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + + private static String[] parsePatterns = { + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", + "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; + + /** + * 获取当前Date型日期 + * + * @return Date() 当前日期 + */ + public static Date getNowDate() { + return new Date(); + } + + /** + * 获取当前日期, 默认格式为yyyy-MM-dd + * + * @return String + */ + public static String getDate() { + return dateTimeNow(YYYY_MM_DD); + } + + public static final String getTime() { + return dateTimeNow(YYYY_MM_DD_HH_MM_SS); + } + + public static final String dateTimeNow() { + return dateTimeNow(YYYYMMDDHHMMSS); + } + + public static final String dateTimeNow(final String format) { + return parseDateToStr(format, new Date()); + } + + public static final String dateTime(final Date date) { + return parseDateToStr(YYYY_MM_DD, date); + } + + public static final String parseDateToStr(final String format, final Date date) { + return new SimpleDateFormat(format).format(date); + } + + public static final Date dateTime(final String format, final String ts) { + try { + return new SimpleDateFormat(format).parse(ts); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * 日期路径 即年/月/日 如2018/08/08 + */ + public static final String datePath() { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyy/MM/dd"); + } + + /** + * 日期路径 即年/月/日 如20180808 + */ + public static final String dateTime() { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyyMMdd"); + } + + /** + * 日期型字符串转化为日期 格式 + */ + public static Date parseDate(Object str) { + if (str == null) { + return null; + } + try { + return parseDate(str.toString(), parsePatterns); + } catch (ParseException e) { + return null; + } + } + + /** + * 获取服务器启动时间 + */ + public static Date getServerStartDate() { + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new Date(time); + } + + /** + * 计算相差天数 + */ + public static int differentDaysByMillisecond(Date date1, Date date2) { + return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24))); + } + + /** + * 计算两个时间差 + */ + public static String getDatePoor(Date endDate, Date nowDate) { + long nd = 1000 * 24 * 60 * 60; + long nh = 1000 * 60 * 60; + long nm = 1000 * 60; + // long ns = 1000; + // 获得两个时间的毫秒时间差异 + long diff = endDate.getTime() - nowDate.getTime(); + // 计算差多少天 + long day = diff / nd; + // 计算差多少小时 + long hour = diff % nd / nh; + // 计算差多少分钟 + long min = diff % nd % nh / nm; + // 计算差多少秒//输出结果 + // long sec = diff % nd % nh % nm / ns; + return day + "天" + hour + "小时" + min + "分钟"; + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/utils/HttpServletRequestUtil.java b/ss-common/src/main/java/com/zxdmy/excite/common/utils/HttpServletRequestUtil.java new file mode 100644 index 0000000..788d7de --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/utils/HttpServletRequestUtil.java @@ -0,0 +1,172 @@ +package com.zxdmy.excite.common.utils; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import org.springframework.util.StreamUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.charset.Charset; +import java.util.*; + +/** + *

                          + * 描述 + *

                          + * + * @author 沈松 + * @since 2021/12/9 16:54 + */ +public class HttpServletRequestUtil { + + /** + * 获取request对象 + * + * @return request对象 + */ + public static HttpServletRequest getRequest() { + return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); + } + + /** + * 获取请求的URI(非URL) + * + * @return 格式如:/system/user/list?size=10&page=2 + */ + public static String getRequestURI() { + HttpServletRequest request = getRequest(); + // URI中的查询字符串 + String queryString = request.getQueryString(); + // 请求URL中不含字符串 + if (!StringUtils.hasText(queryString)) { + // 只返回URI + return request.getRequestURI(); + } + // 否则返回包含查询的字符串 + return request.getRequestURI() + "?" + queryString; + } + + /** + * 获取浏览器的UA + * + * @return UA对象(Hutool工具箱中的) + */ + public static UserAgent getRequestUserAgent() { + HttpServletRequest request = getRequest(); + return UserAgentUtil.parse(request.getHeader("User-Agent")); + } + + /** + * 获取请求用户的IP + * + * @return IP字符串 + */ + public static String getRemoteIP() { + HttpServletRequest request = getRequest(); + 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("X-Forwarded-For"); + } + 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.getHeader("X-Real-IP"); + } + + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + // 多次反向代理后会有多个IP值,第一个为真实IP。 + int index = ip.indexOf(','); + if (index != -1) { + ip = ip.substring(0, index); + } + return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; + } + + /** + * 取得请求头信息 name:value + */ + public static Map getHeaders() { + HttpServletRequest request = getRequest(); + Map map = new HashMap<>(32); + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String key = (String) headerNames.nextElement(); + String value = request.getHeader(key); + map.put(key, value); + } + return map; + } + + /** + * 获取请求体信息 + */ + public static String getBody() { + HttpServletRequest request = getRequest(); + InputStream inputStream = null; + try { + inputStream = request.getInputStream(); + return StreamUtils.copyToString(inputStream, Charset.forName("utf-8")); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + + } + } + } + return StrUtil.EMPTY; + } + + public static String getAllRequestInfo() { + StringBuilder sb = new StringBuilder(); + sb.append("请求详情为:").append(StrUtil.CRLF); + sb.append("RemoteAddress: ").append(getRemoteIP()).append(StrUtil.CRLF); + sb.append("Method: ").append(getRequest().getMethod()).append(StrUtil.CRLF); + sb.append("URI: ").append(getRequestURI()).append(StrUtil.CRLF); + sb.append("Headers: ").append(StrUtil.join(StrUtil.CRLF + " ", mapToList(getHeaders()))).append(StrUtil.CRLF); + sb.append("Body: ").append(getBody()).append(StrUtil.CRLF); + return sb.toString(); + } + + private static List mapToList(Map parameters) { + List parametersList = new ArrayList(); + parameters.forEach((name, value) -> { + parametersList.add(name + "=" + value); + }); + return parametersList; + } + + public static String getHostName() { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + System.out.println(e.getMessage()); + } + return "未知"; + } + + public static String getHostIp() { + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + System.out.println(e.getMessage()); + } + return "127.0.0.1"; + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/utils/KaptchaMathOneTextCreator.java b/ss-common/src/main/java/com/zxdmy/excite/common/utils/KaptchaMathOneTextCreator.java new file mode 100644 index 0000000..ede1502 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/utils/KaptchaMathOneTextCreator.java @@ -0,0 +1,28 @@ +package com.zxdmy.excite.common.utils; + +import com.google.code.kaptcha.text.impl.DefaultTextCreator; + +import java.security.SecureRandom; +import java.util.Map; +import java.util.Random; + +/** + *

                          + * 验证码随机文本生成器之:一位数的加减乘除 + *

                          + * + * @author 沈松 + * @since 2021-10-04 0004 20:24 + */ +public class KaptchaMathOneTextCreator extends DefaultTextCreator { + + @Override + public String getText() { +// Random random = new SecureRandom(); + SecureRandom random = new SecureRandom(); + // 生成两个随机数,随机数范围:[0,10),并返回结果 + Map result = MyCaptchaUtil.mathTextCreator(random.nextInt(10), random.nextInt(10)); + return result.get("resultString"); + } + +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/utils/KaptchaMathTwoTextCreator.java b/ss-common/src/main/java/com/zxdmy/excite/common/utils/KaptchaMathTwoTextCreator.java new file mode 100644 index 0000000..01dbe43 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/utils/KaptchaMathTwoTextCreator.java @@ -0,0 +1,28 @@ +package com.zxdmy.excite.common.utils; + +import com.google.code.kaptcha.text.impl.DefaultTextCreator; + +import java.security.SecureRandom; +import java.util.Map; +import java.util.Random; + +/** + *

                          + * 验证码随机文本生成器之:两位数的加减乘除 + *

                          + * + * @author 沈松 + * @since 2021-10-04 0004 20:26 + */ +public class KaptchaMathTwoTextCreator extends DefaultTextCreator { + + @Override + public String getText() { +// Random random = new SecureRandom(); + SecureRandom random = new SecureRandom(); + // 保存计算结果 + Map result = MyCaptchaUtil.mathTextCreator(random.nextInt(100), random.nextInt(100)); + // 生成两个随机数,随机数范围:[0,100),并返回结果 + return result.get("resultString"); + } +} diff --git a/ss-common/src/main/java/com/zxdmy/excite/common/utils/MyCaptchaUtil.java b/ss-common/src/main/java/com/zxdmy/excite/common/utils/MyCaptchaUtil.java new file mode 100644 index 0000000..af7ac58 --- /dev/null +++ b/ss-common/src/main/java/com/zxdmy/excite/common/utils/MyCaptchaUtil.java @@ -0,0 +1,71 @@ +package com.zxdmy.excite.common.utils; + +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +/** + *

                          + * 自定义的验证码工具类 + *

                          + * + * @author 沈松 + * @since 2021-10-04 0004 20:54 + */ +public class MyCaptchaUtil { + + /** + * 生成数学文本算式 + * + * @param a 数字 + * @param b 数字 + * @return 字符 + */ + public static Map mathTextCreator(int a, int b) { + SecureRandom random = new SecureRandom(); +// Random random = new SecureRandom(); + // 生成随机操作,操作范围:[0,4),分别表示: + - * / + int op = random.nextInt(4); + // 定义计算的结果 + Integer result = 0; + // 定义构建的算式字符串 + StringBuilder resultString = new StringBuilder(); + // 运算符:- + if (1 == op) { + if (a >= b) { + result = a - b; + resultString.append(a).append("-").append(b).append("=?@").append(result); + } else { + result = b - a; + resultString.append(b).append("-").append(a).append("=?@").append(result); + } + } + // * + else if (2 == op) { + result = a * b; + resultString.append(a).append("*").append(b).append("=?@").append(result); + } + // / + else if (3 == op) { + if (a != 0 && b % a == 0) { + result = b / a; + resultString.append(b).append("/").append(a).append("=?@").append(result); + } else if (b != 0 && a % b == 0) { + result = a / b; + resultString.append(a).append("/").append(b).append("=?@").append(result); + } else { + return mathTextCreator(a, b); + } + } + // + + else { + result = b + a; + resultString.append(a).append("+").append(b).append("=?@").append(result); + } + Map ret = new HashMap(); + ret.put("resultCode", result.toString()); + ret.put("resultString", resultString.toString()); + return ret; + } +} diff --git a/ss-common/src/main/resources/mapper/GlobalConfigMapper.xml b/ss-common/src/main/resources/mapper/GlobalConfigMapper.xml new file mode 100644 index 0000000..3d2a0da --- /dev/null +++ b/ss-common/src/main/resources/mapper/GlobalConfigMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + id, conf_service, conf_key, conf_value, encrypt, create_time, update_time, delete_time + + + diff --git a/ss-component/README.md b/ss-component/README.md new file mode 100644 index 0000000..b4f0f15 --- /dev/null +++ b/ss-component/README.md @@ -0,0 +1,3 @@ +# Ss-Component 模块 + +主要实现各种第三方Spring组件服务。 diff --git a/ss-component/pom.xml b/ss-component/pom.xml new file mode 100644 index 0000000..8618196 --- /dev/null +++ b/ss-component/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + + com.zxdmy.excite + shensong + 2.0.0 + + + ss-component + 2.0.0 + ss-component + ss-component + + + + + com.zxdmy.excite + ss-common + 2.0.0 + + + + + + com.qiniu + qiniu-java-sdk + 7.9.3 + + + + + com.aliyun + dysmsapi20170525 + 2.0.8 + + + + + com.aliyun.oss + aliyun-sdk-oss + 3.13.2 + + + + + me.zhyd.oauth + JustAuth + 1.16.5 + + + + + com.alipay.sdk + alipay-easysdk + 2.2.1 + + + + + com.github.binarywang + weixin-java-pay + 4.2.2.B + + + + + + diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/alipay/AlipayService.java b/ss-component/src/main/java/com/zxdmy/excite/component/alipay/AlipayService.java new file mode 100644 index 0000000..32e899d --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/alipay/AlipayService.java @@ -0,0 +1,362 @@ +package com.zxdmy.excite.component.alipay; + +import cn.hutool.core.util.IdUtil; +import com.alipay.easysdk.factory.Factory; +import com.alipay.easysdk.kernel.Config; +import com.alipay.easysdk.kernel.util.ResponseChecker; +import com.alipay.easysdk.payment.app.models.AlipayTradeAppPayResponse; +import com.alipay.easysdk.payment.common.models.AlipayDataDataserviceBillDownloadurlQueryResponse; +import com.alipay.easysdk.payment.common.models.AlipayTradeFastpayRefundQueryResponse; +import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse; +import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse; +import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse; +import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse; +import com.alipay.easysdk.payment.wap.models.AlipayTradeWapPayResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.common.service.IGlobalConfigService; +import com.zxdmy.excite.component.bo.AlipayBO; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * 支付宝支付服务实现类 + * https://github.com/alipay/alipay-easysdk/tree/master/java + * + * @author 沈松 + * @since 2022-01-02 0002 23:31 + */ +@Service +@AllArgsConstructor +public class AlipayService { + + private IGlobalConfigService configService; + + private static final String DEFAULT_SERVICE = "alipay"; + + private static final String DEFAULT_KEY = "alipay"; + + /** + * 保存信息至数据库 + * + * @param alipayBO 支付宝支付培配置信息 + * @return 保存结果:T|F + */ + public boolean saveConfig(AlipayBO alipayBO) { + // 必填信息不能为空 + if (null == alipayBO.getAppId() || null == alipayBO.getMerchantPrivateKey()) { + throw new ServiceException("APPID和应用私钥不能为空,请检查!"); + } + // 如果支付宝公钥为空,则三个证书不能为空 + if (null == alipayBO.getAlipayPublicKey()) + if (null == alipayBO.getMerchantCertPath() || null == alipayBO.getAlipayCertPath() || null == alipayBO.getAlipayRootCertPath()) + throw new ServiceException("证书模式下,[应用公钥证书][支付宝公钥证书][支付宝根证书]不能为空,请检查!"); + // 保存信息至数据库 + try { + return configService.save(DEFAULT_SERVICE, alipayBO.getKey() != null ? alipayBO.getKey() : DEFAULT_KEY, alipayBO, true); + } catch (JsonProcessingException e) { + throw new ServiceException(e.getMessage()); + } + } + + /** + * 从数据库读取配置信息(指定KEY) + * + * @param confKey 本条支付信息的KEY,如果为null,读取默认KEY + * @return 支付宝支付配置信息 + */ + public AlipayBO getConfig(String confKey) { + if (null == confKey) { + return this.getConfig(); + } + return (AlipayBO) configService.get(DEFAULT_SERVICE, confKey, new AlipayBO()); + } + + /** + * 从数据库读取配置信息(默认KEY) + * + * @return 支付宝支付配置信息 + */ + public AlipayBO getConfig() { + return this.getConfig(DEFAULT_KEY); + } + + /** + * 统一支付服务接口(当面付、电脑网站支付、手机网站支付、APP支付) + * + * @param confKey 支付宝配置信息的KEY。如果加载默认的KEY,输入null + * @param payType 支付类型:当面付(faceToFace),电脑网站支付(page),手机网站支付(wap),APP支付(app) + * @param subject 商品名称 + * @param outTradeNo 商户订单号:商户内唯一 + * @param totalAmount 总金额(单位:元),实例:12.34 + * @param returnUrl 支付成功后跳转页面(只针对网站支付有效) + * @param quitUrl 支付取消跳转页面(只针对手机网站支付有效) + * @return 返回结果:当面付为二维码链接,其他均为网站Body代码 + */ + public String pay(String confKey, String payType, String subject, String outTradeNo, String totalAmount, String returnUrl, String quitUrl) { + // 必填信息不能为空 + if (null == subject || null == outTradeNo || null == totalAmount) { + throw new ServiceException("商品名称、商户订单号、商品价格不能为空!"); + } + // 1. 设置参数 + Factory.setOptions(this.getOptions(confKey)); + try { + // 2. 调用API发起创建支付 + switch (payType.toLowerCase()) { + // 当面付 + case "facetoface": + // 创建订单 + AlipayTradePrecreateResponse response = Factory.Payment.FaceToFace().preCreate(subject, outTradeNo, totalAmount); + // 成功? + if (ResponseChecker.success(response)) + return response.getQrCode(); + break; + // 电脑网站支付 + case "page": + if (null == returnUrl) { + throw new ServiceException("电脑网站支付的跳转地址(returnUrl)不能为空!"); + } + // 调用接口 + AlipayTradePagePayResponse response1 = Factory.Payment.Page().pay(subject, outTradeNo, totalAmount, returnUrl); + // 成功? + if (ResponseChecker.success(response1)) + return response1.getBody(); + break; + // 手机网站支付 + case "wap": + if (null == returnUrl || null == quitUrl) { + throw new ServiceException("手机网站支付的失败退出地址(quitUrl)、成功跳转地址(returnUrl)不能为空!"); + } + AlipayTradeWapPayResponse response2 = Factory.Payment.Wap().pay(subject, outTradeNo, totalAmount, quitUrl, returnUrl); + // 成功 + if (ResponseChecker.success(response2)) + return response2.getBody(); + break; + // APP支付 + case "app": + AlipayTradeAppPayResponse response3 = Factory.Payment.App().pay(subject, outTradeNo, totalAmount); + // 成功 + if (ResponseChecker.success(response3)) + return response3.getBody(); + break; + // 其他类型:错误 + default: + throw new ServiceException("输入的支付类型[" + payType + "]不在许可支付类型范围内。许可类型:当面付(faceToFace),电脑网站支付(page),手机网站支付(wap),APP支付(app)"); + } + } catch (Exception e) { + System.err.println("调用遭遇异常,原因:" + e.getMessage()); + throw new ServiceException(e.getMessage()); + } + return null; + } + + /** + * 查询支付订单接口 + * + * @param confKey 可选:支付宝配置信息的KEY。如果加载默认的KEY,输入null + * @param tradeNo 特殊可选:支付宝交易号(订单号) + * @param outTradeNo 特殊可选:商家订单号 + * @return 查询成功:{ 0:Y,1:支付宝交易号,2:商家订单号,3:交易状态,4:订单金额,5:买家ID,6:买家支付宝账号 }
                          查询失败:{ E,错误代码,错误描述 } + * @apiNote tradeNo 和 outTradeNo 不能同时为空。同时存在优先取 tradeNo。 + */ + public String[] queryPay(String confKey, String tradeNo, String outTradeNo) { + // 判断 + if (null == tradeNo && null == outTradeNo) { + throw new ServiceException("tradeNo 和 outTradeNo 不能同时为空!"); + } + // 设置参数 + Factory.setOptions(this.getOptions(confKey)); + try { + // 执行查询 + AlipayTradeQueryResponse response = Factory.Payment.Common().optional("trade_no", tradeNo).query(outTradeNo); + // 请求成功(即返回信息中没有sub_code) + if (ResponseChecker.success(response)) { + return new String[]{ + "Y", + response.tradeNo, + response.outTradeNo, + response.tradeStatus, + response.totalAmount, + response.buyerUserId, + response.buyerLogonId + }; + } else { + return new String[]{"E", response.subCode, response.subMsg}; + } + } catch (Exception e) { + System.err.println("调用遭遇异常,原因:" + e.getMessage()); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 退款接口(支持部分退款) + * + * @param confKey 可选:支付宝配置信息的KEY。如果加载默认的KEY,输入null + * @param tradeNo 特殊可选:商户订单号 + * @param outTradeNo 特殊可选:商户订单号 + * @param refundAmount 必填:退款金额 + * @param reason 可选:退款原因 + * @return 本次请求退款成功:{ 0:Y,1:支付宝交易号,2:商家订单号,3:退款请求号,4:总退款金额 }
                          + * 历史请求退款成功:{ 0:N,1:支付宝交易号,2:商家订单号,3:退款请求号,4:退款金额 }
                          + * 退款发生错误:{ 0:E,1:错误代码,2:错误描述 } + * @apiNote tradeNo 和 outTradeNo 不能同时为空。同时存在优先取 tradeNo。 + */ + public String[] refund(String confKey, String tradeNo, String outTradeNo, String refundAmount, String reason) { + // 判断 + if (null == tradeNo && null == outTradeNo) { + throw new ServiceException("tradeNo 和 outTradeNo 不能同时为空!"); + } + // 设置参数 + Factory.setOptions(this.getOptions(confKey)); + try { + // 生成唯一的款请求号 + String outRequestNo = IdUtil.simpleUUID(); + // 发起请求 + AlipayTradeRefundResponse response = Factory.Payment.Common() + // 支付宝交易号 + .optional("trade_no", tradeNo) + // 退款原因 + .optional("refund_reason", reason) + // 退款请求号 + .optional("out_request_no", outRequestNo) + // 执行退款 + .refund(outTradeNo, refundAmount); + // 如果请求成功(即返回信息中没有sub_code) + if (ResponseChecker.success(response)) { + return new String[]{ + // 本次请求退款状态(即资金有改变,详情:https://opensupport.alipay.com/support/knowledge/27585/201602348776 ) + response.fundChange, + response.tradeNo, + response.outTradeNo, + outRequestNo, + response.refundFee + }; + } else { + return new String[]{"E", response.subCode, response.subMsg}; + } + } catch (Exception e) { + System.err.println("调用遭遇异常,原因:" + e.getMessage()); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 查询退款 + * + * @param confKey 可选:支付宝配置信息的KEY。如果加载默认的KEY,输入null + * @param outTradeNo 必填:商户订单号 + * @param outRequestNo 必填:退款请求号 + * @return 已退款:{ Y,支付宝交易号,商家订单号,退款请求号,订单金额,退款金额,退款原因 }
                          未退款:{ N,描述 }
                          发生错误:{ E,错误代码,错误描述 } + */ + public String[] queryRefund(String confKey, String outTradeNo, String outRequestNo) { + // 设置参数 + Factory.setOptions(this.getOptions(confKey)); + // 如果请求号为空,则表示全额退款,设置请求号位商家订单号 + if (null == outRequestNo) { + outRequestNo = outTradeNo; + } + try { + // 发起请求 + AlipayTradeFastpayRefundQueryResponse response = Factory.Payment.Common().queryRefund(outTradeNo, outRequestNo); + // 如果请求成功(即返回信息中没有sub_code) + if (ResponseChecker.success(response)) { + // 如果该接口返回了查询数据,则代表退款成功(详情:https://opensupport.alipay.com/support/knowledge/27585/201602348776 ) + if (null != response.refundAmount) { + return new String[]{ + "Y", + response.tradeNo, + response.outTradeNo, + response.outRequestNo, + response.totalAmount, + response.refundAmount, + response.refundReason + }; + } else { + return new String[]{ + "N", + "该订单未退款或输入的退款请求号有误,请检查!" + }; + } + } else { + return new String[]{"E", response.subCode, response.subMsg}; + } + } catch (Exception e) { + System.err.println("调用遭遇异常,原因:" + e.getMessage()); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 下载对账单(不能查询当天或当月的) + * https://developer.aliyun.com/article/710922 + * + * @param confKey 可选:支付宝配置信息的KEY。如果加载默认的KEY,输入null + * @param date 必填:交易的具体日期(如2022-01-01)或月份(2021-12) + * @return 获取成功:{Y,下载URL}
                          发生错误:{ E,错误代码,错误描述 } + */ + public String[] downloadBill(String confKey, String date) { + // 设置参数 + Factory.setOptions(this.getOptions(confKey)); + try { + // 发送请求 + AlipayDataDataserviceBillDownloadurlQueryResponse response = Factory.Payment.Common().downloadBill("trade", date); + + // 如果请求成功(即返回信息中没有sub_code) + if (ResponseChecker.success(response)) { + return new String[]{ + "Y", + response.billDownloadUrl + }; + } else { + return new String[]{"E", response.subCode, response.subMsg}; + } + + } catch (Exception e) { + System.err.println("调用遭遇异常,原因:" + e.getMessage()); + throw new ServiceException(e.getMessage()); + } + } + + + /** + * 读取配置信息 + * + * @param confKey 支付宝配置信息的KEY。如果加载默认的KEY,输入null + * @return 配置信息 + */ + private Config getOptions(String confKey) { + // 从数据库中读取配置信息 + AlipayBO alipayBO = this.getConfig(confKey); + // 将配置信息写入支付宝支付配置类中 + Config config = new Config(); + config.protocol = alipayBO.getProtocol(); + config.gatewayHost = alipayBO.getGatewayHost(); + config.signType = alipayBO.getSignType(); + + config.appId = alipayBO.getAppId(); + + // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中 + config.merchantPrivateKey = alipayBO.getMerchantPrivateKey(); + // 如果三个证书不为空,则优先设置三个证书 + if (null != alipayBO.getMerchantCertPath() && null != alipayBO.getAlipayCertPath() && null != alipayBO.getAlipayRootCertPath()) { + //注:证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径,优先从文件系统中加载,加载失败后会继续尝试从CLASS_PATH中加载 + config.merchantCertPath = alipayBO.getMerchantCertPath(); + config.alipayCertPath = alipayBO.getAlipayCertPath(); + config.alipayRootCertPath = alipayBO.getAlipayRootCertPath(); + } else if (null != alipayBO.getAlipayPublicKey()) { + //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可 + config.alipayPublicKey = alipayBO.getAlipayPublicKey(); + } else { + throw new ServiceException("配置信息有误:证书模式配置不完整或未配置公钥模式,请检查!"); + } + + //可设置异步通知接收服务地址(可选) + config.notifyUrl = alipayBO.getNotifyUrl(); + + //可设置AES密钥,调用AES加解密相关接口时需要(可选) + config.encryptKey = alipayBO.getEncryptKey(); + + return config; + } +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/aliyun/AliyunOssService.java b/ss-component/src/main/java/com/zxdmy/excite/component/aliyun/AliyunOssService.java new file mode 100644 index 0000000..c6d494b --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/aliyun/AliyunOssService.java @@ -0,0 +1,127 @@ +package com.zxdmy.excite.component.aliyun; + +import cn.hutool.core.codec.Base64; +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.model.PolicyConditions; +import com.aliyun.oss.model.PutObjectResult; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.common.service.IGlobalConfigService; +import com.zxdmy.excite.component.bo.AliyunOssBO; +import com.zxdmy.excite.component.bo.AliyunSmsBO; +import com.zxdmy.excite.component.vo.AliyunOssPolicyVO; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.util.Date; + +/** + * 阿里云对象存储服务 + * + * @author 沈松 + * @since 2022/1/5 20:37 + */ +@Service +@AllArgsConstructor +public class AliyunOssService { + + IGlobalConfigService configService; + + private static final String DEFAULT_SERVICE = "aliyunOss"; + + private static final String DEFAULT_KEY = "aliyunOss"; + + public boolean saveConfig(AliyunOssBO aliyunOssBO) throws JsonProcessingException { + if (null == aliyunOssBO.getBucketName() || null == aliyunOssBO.getBucketDomain() || null == aliyunOssBO.getEndpoint() || null == aliyunOssBO.getAccessKeyId() || null == aliyunOssBO.getAccessKeySecret()) { + throw new ServiceException("部分参数为空,请检查!"); + } + if (null == aliyunOssBO.getKey()) { + return configService.save(DEFAULT_SERVICE, DEFAULT_KEY, aliyunOssBO, true); + } else { + return configService.save(DEFAULT_SERVICE, aliyunOssBO.getKey(), aliyunOssBO, true); + } + } + + public AliyunOssBO getConfig(String confKey) { + AliyunOssBO aliyunOssBO = new AliyunOssBO(); + return (AliyunOssBO) configService.get(DEFAULT_SERVICE, confKey, aliyunOssBO); + } + + public AliyunOssBO getConfig() { + return this.getConfig(DEFAULT_KEY); + } + + + + /** + * 前端直传用的方法 + * + * @return + */ + public AliyunOssPolicyVO createUploadToken(String confKey, String fileName, Long expireTime) { + // 读取秘钥等信息 + AliyunOssBO aliyunOssBO = this.getConfig(confKey); + // 创建OSSClient实例。 + OSS oss = new OSSClientBuilder().build(aliyunOssBO.getEndpoint(), aliyunOssBO.getAccessKeyId(), aliyunOssBO.getAccessKeySecret()); + + PolicyConditions policyConditions = new PolicyConditions(); + // 策略:最大上传文件1G + policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000); + + long expireEndTime = System.currentTimeMillis() + expireTime * 1000; + Date expireEndDate = new Date(expireEndTime); + try { + // 生成上传策略 + String postPolicy = oss.generatePostPolicy(expireEndDate, policyConditions); + // 生成签名 + String postSignature = oss.calculatePostSignature(postPolicy); + // 策略转码 + String base64Policy = Base64.encode(postPolicy); + + // 构造返回数据 + return new AliyunOssPolicyVO() + .setAccessKeyId(aliyunOssBO.getAccessKeyId()) + .setPolicy(base64Policy) + .setSignature(postSignature) + .setHost(aliyunOssBO.getBucketDomain()) + .setCallback("") + .setKey(fileName); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } finally { + oss.shutdown(); + } + } + + /** + * 前端直传用的方法 + * + * @return + */ + public AliyunOssPolicyVO createUploadToken(String fileName, Long expireTime) { + return this.createUploadToken(DEFAULT_KEY, fileName, expireTime); + } + + + public boolean uploadFile(String confKey, File file) { + // 读取配置 + AliyunOssBO aliyunOssBO = this.getConfig(confKey); + // 创建OSSClient实例。 + OSS oss = new OSSClientBuilder().build(aliyunOssBO.getEndpoint(), aliyunOssBO.getAccessKeyId(), aliyunOssBO.getAccessKeySecret()); + try { + PutObjectResult putObjectRequest = oss.putObject(aliyunOssBO.getBucketName(), file.getName(), file); + return putObjectRequest.getResponse().isSuccessful(); + } catch (Exception e) { + System.out.println(e.getMessage()); + return false; + } finally { + oss.shutdown(); + } + } + + public boolean uploadFile(File file) { + return this.uploadFile(DEFAULT_KEY, file); + } +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/aliyun/AliyunSmsService.java b/ss-component/src/main/java/com/zxdmy/excite/component/aliyun/AliyunSmsService.java new file mode 100644 index 0000000..2027ef8 --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/aliyun/AliyunSmsService.java @@ -0,0 +1,184 @@ +package com.zxdmy.excite.component.aliyun; + +import com.aliyun.dysmsapi20170525.Client; +import com.aliyun.dysmsapi20170525.models.SendSmsRequest; +import com.aliyun.dysmsapi20170525.models.SendSmsResponse; +import com.aliyun.teaopenapi.models.Config; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.common.service.IGlobalConfigService; +import com.zxdmy.excite.component.bo.AliyunSmsBO; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * 阿里云短信服务(Short Message Service)实现 + * + * @author 沈松 + * @since 2022-01-02 0002 23:33 + */ +@Service +@AllArgsConstructor +public class AliyunSmsService { + + IGlobalConfigService configService; + + private static final String DEFAULT_SERVICE = "aliyunSms"; + + /** + * 保存阿里云短信服务的开发者信息、消息模板相关信息 + * 注意:同一个系统的消息模板可能有多个,所以 + * + * @param aliyunSmsBO 实体信息,其中KEY必填 + * @return 保存结果 + * @throws JsonProcessingException 异常 + */ + public boolean saveAliyunSmsConfig(AliyunSmsBO aliyunSmsBO) throws JsonProcessingException { + // 如果必填项为空,则返回错误信息 + if (null == aliyunSmsBO.getKey() || null == aliyunSmsBO.getAccessKeyId() || null == aliyunSmsBO.getAccessKeySecret() || null == aliyunSmsBO.getSignName() || null == aliyunSmsBO.getTemplateCode()) { + throw new ServiceException("部分必填信息为空,请检查!"); + } + // 保存 + return configService.save(DEFAULT_SERVICE, aliyunSmsBO.getKey(), aliyunSmsBO, true); + } + + /** + * 通过配置KEY获取短信配置信息 + * + * @param confKey 阿里云短信服务的配置key + * @return 阿里云短信服务实体 + */ + public AliyunSmsBO getAliyunSmsConfig(String confKey) { + AliyunSmsBO aliyunSmsBO = new AliyunSmsBO(); + return (AliyunSmsBO) configService.get(DEFAULT_SERVICE, confKey, aliyunSmsBO); + } + + /** + * 发送短信服务 + * + * @param confKey confKey,当前短信模板配置的key + * @param phone 手机号数组 + * @param templateValue 消息模板中的参数值 + * @return 结果 + */ + public boolean sendSmsOne(String confKey, String phone, String[] templateValue) { + // 从数据库读取配置信息 + AliyunSmsBO aliyunSmsBO = this.getAliyunSmsConfig(confKey); + if (null == aliyunSmsBO) { + throw new ServiceException("阿里云短信服务配置信息有误/不存在,请核实"); + } + // 如果输入的参数个数和配置信息里的参数个数不相等,则返回错误信息 + if (templateValue.length != aliyunSmsBO.getTemplateParam().length) { + throw new ServiceException("templateValue个数有误,请核实"); + } + // 发起短信并获取发送结果 + SendSmsResponse response = this.sendSms(aliyunSmsBO, phone, templateValue, null); + // 结果不为空,进一步判断 + if (response != null) { + // 打印结果 +// System.out.println(response.body.code); // 发送成功为OK +// System.out.println(response.body.message); // 发送成功为OK +// System.out.println(response.body.requestId); // 请求ID +// System.out.println(response.body.bizId); // 请求ID + return "OK".equals(response.body.code); + } + return false; + } + + /** + * 批量发送短信 + * 其中官网中有批量发送短信的接口SendBatchSms。 + * 但我们这里还是逐个发送 + * + * @param confKey 短信模板的key + * @param smsMap 短信map,其中key为手机号,value为String[]数组,其大小与消息模板参数个数一致,并依次对应 + * @return 结果map + */ + public Map sendSmsBatch(String confKey, Map smsMap) { + // 从数据库读取配置信息 + AliyunSmsBO aliyunSmsBO = this.getAliyunSmsConfig(confKey); + if (null == aliyunSmsBO) { + throw new ServiceException("阿里云短信服务配置信息有误,请核实"); + } + int templateLength = aliyunSmsBO.getTemplateParam().length; + // 发起短信并获取发送结果 + SendSmsResponse response; + // 记录结果的map + Map result = new HashMap<>(); + // 遍历map,逐个构造并发送短信 + for (String phone : smsMap.keySet()) { + // 参数值对等,则可以发送 + if (smsMap.get(phone).length == templateLength) { + response = this.sendSms(aliyunSmsBO, phone, smsMap.get(phone), null); + // 发送成功 + if (response != null && "OK".equals(response.body.code)) { + result.put(phone, true); + } + // 发送失败 + else { + result.put(phone, false); + } + } + // 参数值不对等,直接标记失败 + else { + result.put(phone, false); + } + } + return result; + } + + /** + * 私有方法:配置并发送短信实现类 + * + * @param aliyunSmsBO 配置信息 + * @param phone 接收手机号 + * @param templateValue 模板JSON格式的参数 + * @param outId 流水号 + * @return 发送结果 + */ + private SendSmsResponse sendSms(AliyunSmsBO aliyunSmsBO, String phone, String[] templateValue, String outId) { + // 阿里云短信服务信息配置 + Config config = new Config() + // 必填,开发者的 AccessKey ID + .setAccessKeyId(aliyunSmsBO.getAccessKeyId()) + // 必填,开发者的 AccessKey Secret + .setAccessKeySecret(aliyunSmsBO.getAccessKeySecret()) + // 默认,暂时不支持多Region,默认即可 + .setRegionId("cn-hangzhou") + // 默认,产品域名,开发者无需替换 + .setEndpoint("dysmsapi.aliyuncs.com") + // 可选,启用https协议 + .setProtocol("https"); + // 构造请求参数 + StringBuilder templateParam = new StringBuilder("{"); + for (int i = 0; i < aliyunSmsBO.getTemplateParam().length; i++) { + templateParam.append("\"").append(aliyunSmsBO.getTemplateParam()[i]).append("\":\"").append(templateValue[i]).append("\","); + } + templateParam.append("}"); + // 短信请求信息配置 + SendSmsRequest sendSmsRequest = new SendSmsRequest() + // 必填,接收短信的手机号 + .setPhoneNumbers(phone) + // 必填,设置签名名称,应严格按"签名名称"填写,格式如:阿里云 + .setSignName(aliyunSmsBO.getSignName()) + // 必填,设置模板CODE,应严格按"模板CODE"填写,格式:SMS_88888888 + .setTemplateCode(aliyunSmsBO.getTemplateCode()) + // 可选,设置模板参数, 假如模板中存在变量需要替换则为必填项 + .setTemplateParam(templateParam.toString()) + // 可选,设置流水号 + //.setOutId("10086") + ; + // 发起请求 + SendSmsResponse response; + try { + response = new Client(config).sendSms(sendSmsRequest); + } catch (Exception e) { + System.out.println(e.getMessage()); + return null; + } + return response; + } +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/bo/AlipayBO.java b/ss-component/src/main/java/com/zxdmy/excite/component/bo/AlipayBO.java new file mode 100644 index 0000000..fa3cd9a --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/bo/AlipayBO.java @@ -0,0 +1,88 @@ +package com.zxdmy.excite.component.bo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 支付宝支付配置信息 + * + * @author 沈松 + * @since 2022/1/10 22:13 + */ +@Data +@Accessors(chain = true) +public class AlipayBO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 本条支付宝支付信息的KEY + */ + private String key; + + /** + * 必填:应用AppId,例如:2019091767145019 + */ + private String appId; + + /** + * 必填:应用名称 + */ + private String appName; + + /** + * 必填:应用私钥(Java语言),例如:MIIEvQIBADANB ... ... + */ + private String merchantPrivateKey; + + // 接口加签方式分:证书模式(收、退款)和公钥模式(只能收款) + // 证书模式文档:https://opendocs.alipay.com/common/02kipl + // 优先级:证书模式 > 非证书模式 + + /** + * 证书模式:【应用公钥证书】文件路径,路径优先级:文件系统 > CLASS_PATH + */ + private String merchantCertPath; + + /** + * 证书模式:【支付宝公钥证书】文件路径,路径优先级:文件系统 > CLASS_PATH + */ + private String alipayCertPath; + + /** + * 证书模式:【支付宝根证书】文件路径,路径优先级:文件系统 > CLASS_PATH + */ + private String alipayRootCertPath; + + /** + * 公钥模式:只需要填写此【支付宝公钥】即可,无需赋值上面的三个证书路径 + */ + private String alipayPublicKey; + + /** + * 可选:异步通知接收服务地址,例如:https://www.test.com/callback + */ + private String notifyUrl; + + /** + * 可选:AES密钥(接口内容加密方式),调用AES加解密相关接口时需要 + */ + private String encryptKey; + + /** + * 必填:协议类型:http | https 二选一 + */ + private String protocol = "https"; + + /** + * 必填:gatewayHost,默认:openapi.alipay.com + */ + private String gatewayHost = "openapi.alipay.com"; + + /** + * 必填:签名类型,默认RSA2 + */ + private String signType = "RSA2"; +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/bo/AliyunOssBO.java b/ss-component/src/main/java/com/zxdmy/excite/component/bo/AliyunOssBO.java new file mode 100644 index 0000000..0600fe1 --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/bo/AliyunOssBO.java @@ -0,0 +1,57 @@ +package com.zxdmy.excite.component.bo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 阿里云OSS配置信息 + * + * @author 沈松 + * @since 2022/1/5 20:18 + */ +@Data +@Accessors(chain = true) +public class AliyunOssBO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 本条OSS配置信息的key + */ + private String key; + + /** + * OSS上的命名空间 + */ + private String bucketName; + + /** + * Bucket的域名,由阿里云官方生成,该域名用来访问空间中的文件。 + */ + private String bucketDomain; + + /** + * 自己通过CNAME域名解析绑定的域名 + */ + private String bindDomain; + + /** + * 访问域名(地域节点),上传使用。 + * 详情请参考:https://help.aliyun.com/document_detail/31837.html + */ + private String endpoint; + + /** + * 阿里云账号(建议使用子账号)的AccessKey + */ + private String accessKeyId; + + /** + * 阿里云账号(建议使用子账号)的AccessKey的秘钥 + */ + private String accessKeySecret; + + +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/bo/AliyunSmsBO.java b/ss-component/src/main/java/com/zxdmy/excite/component/bo/AliyunSmsBO.java new file mode 100644 index 0000000..2b18e69 --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/bo/AliyunSmsBO.java @@ -0,0 +1,49 @@ +package com.zxdmy.excite.component.bo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 阿里云短信服务配置信息 + * + * @author 沈松 + * @since 2022/1/3 20:28 + */ +@Data +@Accessors(chain = true) +public class AliyunSmsBO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 本条短信配置信息的key + */ + private String key; + + /** + * 必填。开发者的 AccessKey ID + */ + private String accessKeyId; + + /** + * 必填。开发者的 AccessKey Secret + */ + private String accessKeySecret; + + /** + * 必填。短信模板的签名,严格按照"签名名称"填写,格式如:阿里云 + */ + private String signName; + + /** + * 必填。模板CODE,应严格按"模板CODE"填写,格式:SMS_88888888 + */ + private String templateCode; + + /** + * 选填。如果消息模板中有参数,则必填。设置模板参数,如:[code,data] + */ + private String[] templateParam; +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/bo/JustAuthBO.java b/ss-component/src/main/java/com/zxdmy/excite/component/bo/JustAuthBO.java new file mode 100644 index 0000000..b1b7f95 --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/bo/JustAuthBO.java @@ -0,0 +1,59 @@ +package com.zxdmy.excite.component.bo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 第三方登录的配置信息实体 + * + * @author 沈松 + * @since 2022/1/6 17:30 + */ +@Data +@Accessors(chain = true) +public class JustAuthBO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 本条登录类型的KEY,如:qq、weibo等 + */ + private String key; + + /** + * 客户端id:对应各平台的appKey + */ + private String appID; + + /** + * 客户端Secret:对应各平台的appSecret + */ + private String appSecret; + + /** + * 登录成功后的回调地址 + */ + private String redirectUri; + + /** + * 只针对qq登录生效:是否需要申请unionid + */ + private Boolean unionId; + + /** + * 企业微信第三方授权用户类型:member|admin + */ + private String usertype; + + /** + * 企业微信登录:授权方的网页应用ID + */ + private String agentId; + + /** + * 支付宝的公钥,只针对支付宝、阿里云登陆有效 + */ + private String publicKey; +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/bo/QiniuOssBO.java b/ss-component/src/main/java/com/zxdmy/excite/component/bo/QiniuOssBO.java new file mode 100644 index 0000000..370345f --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/bo/QiniuOssBO.java @@ -0,0 +1,70 @@ +package com.zxdmy.excite.component.bo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + *

                          + * 描述 + *

                          + * + * @author 沈松 + * @since 2022/1/3 16:07 + */ +@Data +@Accessors(chain = true) +public class QiniuOssBO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 本条七牛云配置信息的key(主键) + */ + private String key; + + /** + * 七牛云账号的秘钥管理之:AccessKey + */ + @NotBlank(message = "AccessKey不能为空") + private String accessKey; + + /** + * 七牛云账号的秘钥管理之:SecretKey + */ + @NotBlank(message = "SecretKey不能为空") + private String secretKey; + + /** + * 七牛云空间名称 + */ + @NotBlank(message = "空间名称不能为空") + private String bucket; + + /** + * 七牛云该空间(bucket)绑定的CDN加速域名 + */ + @NotBlank(message = "CDN加速域名不能为空") + private String domain; + + /** + * 地域选择:https://developer.qiniu.com/kodo/1671/region-endpoint-fq + * 华东:z0; 华北:z1; 华南:z2; 北美:na0; 东南亚:as0; 华东-浙江2:cn-east-2 + * 可以为空,填写其他字符,由系统自己选 + */ +// @NotBlank(message = "地域不能为空") + private String region; + + /** + * 七牛云该空间(bucket)绑定的CDN加速域名的协议 http | https + */ + @NotBlank(message = "CDN加速域名协议不能为空") + private String protocol; + + /* + * 上传Token + */ + private String uploadToken; +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/bo/WeChatPayBO.java b/ss-component/src/main/java/com/zxdmy/excite/component/bo/WeChatPayBO.java new file mode 100644 index 0000000..4cc040c --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/bo/WeChatPayBO.java @@ -0,0 +1,77 @@ +package com.zxdmy.excite.component.bo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + *

                          + * 描述 + *

                          + * + * @author 沈松 + * @since 2022/1/9 20:27 + */ +@Data +@Accessors(chain = true) +public class WeChatPayBO implements Serializable { + + private static final long serialVersionUID = 1L; + + + /** + * 本条微信支付配置信息的key(主键) + */ + private String key; + + /** + * 设置微信公众号或者小程序等的appid + */ + private String appId; + + /** + * 微信支付商户号 + */ + private String mchId; + + /** + * 设置APIv2密钥(微信支付商户密钥 + */ + private String mchKey; + + /** + * APIv3密钥(微信支付商户密钥 + */ + private String apiV3Key; + /** + * 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除 + */ + private String subAppId; + + /** + * 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除 + */ + private String subMchId; + + /** + * V2:apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定 + */ + private String keyPath; + + /** + * V3:key.pem文件的绝对路径,或者如果放在项目中,请以classpath:开头指定 + */ + private String privateKeyPath; + + /** + * V3:cert.pem文件的绝对路径,或者如果放在项目中,请以classpath:开头指定 + */ + private String privateCertPath; + + /** + * 通知地址.通知url必须为外网可访问的url,不能携带参数。公网域名必须为https。 + */ + private String notifyUrl; + +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/justauth/JustAuthService.java b/ss-component/src/main/java/com/zxdmy/excite/component/justauth/JustAuthService.java new file mode 100644 index 0000000..74f3276 --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/justauth/JustAuthService.java @@ -0,0 +1,281 @@ +package com.zxdmy.excite.component.justauth; + +import cn.hutool.core.util.DesensitizedUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.common.service.IGlobalConfigService; +import com.zxdmy.excite.component.bo.JustAuthBO; +import lombok.AllArgsConstructor; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.enums.scope.AuthGiteeScope; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.*; +import me.zhyd.oauth.utils.AuthScopeUtils; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 第三方登录服务接口 + * + * @author 沈松 + * @since 2022/1/6 12:02 + */ +@Service +@AllArgsConstructor +public class JustAuthService { + + IGlobalConfigService configService; + + private static final String DEFAULT_SERVICE = "justAuth"; + + private static final Set CONF_KEY_SET = new HashSet() {{ + add("qq"); + add("weibo"); + add("wechat_open"); + add("wechat_mp"); + add("wechat_enterprise"); + add("baidu"); + add("dingtalk"); + add("aliyun"); + add("alipay"); + add("huawei"); + add("feishu"); + add("gitee"); + add("github"); + }}; + + + /** + * 保存配置信息 + * + * @param authBO 配置信息类 + * @return 保存结果 + */ + public boolean saveConfig(JustAuthBO authBO) throws JsonProcessingException { + // 配置信息的key必须存在于当前的库中 + if (null != authBO.getKey() && CONF_KEY_SET.contains(authBO.getKey())) { + // 三大必填信息不能为空 + if (null == authBO.getAppID() || null == authBO.getAppSecret() || null == authBO.getRedirectUri()) { + throw new ServiceException("APPID、APPSecret和RedirectUri不能为空!请检查!"); + } else { + return configService.save(DEFAULT_SERVICE, authBO.getKey(), authBO, true); + } + } else { + throw new ServiceException("当前输入的配置KEY[" + authBO.getKey() + "]不在许可范围内,请检查!"); + } + } + + /** + * 根据配置的KEY获取一条配置信息 + * + * @param confKey 配置的KEY + * @return 指定KEY的配置信息 + */ + public JustAuthBO getConfig(String confKey) { + // 配置信息的key必须存在于当前的库中 + if (!CONF_KEY_SET.contains(confKey)) { + throw new ServiceException("当前输入的配置KEY[" + confKey + "]不在许可范围内,请检查!"); + } + JustAuthBO justAuthBO = new JustAuthBO(); + return (JustAuthBO) configService.get(DEFAULT_SERVICE, confKey, justAuthBO); + } + + /** + * 获取所有的登录配置信息 + * + * @param desensitized 是否脱敏 + * @return 配置列表 + */ + public List getConfigList(Boolean desensitized) { + JustAuthBO justAuthBO = new JustAuthBO(); + List objectList = configService.getList(DEFAULT_SERVICE, justAuthBO); + ObjectMapper objectMapper = new ObjectMapper(); + List justAuthBOList = new ArrayList<>(); + for (Object o : objectList) { + justAuthBO = objectMapper.convertValue(o, justAuthBO.getClass()); + if (desensitized) { + justAuthBO.setAppSecret(DesensitizedUtil.idCardNum(justAuthBO.getAppSecret(), 2, 2)); + justAuthBO.setPublicKey(DesensitizedUtil.idCardNum(justAuthBO.getPublicKey(), 2, 2)); + } + justAuthBOList.add(justAuthBO); + } + return justAuthBOList; + } + + /** + * 生成登录授权的URL + * + * @param confKey 配置的KEY,也即授权来源(如qq、weibo等) + * @param state 状态码(字符串) + * @return 登录的链接 + */ + public String createAuthorizeUrl(String confKey, String state) { + if (!CONF_KEY_SET.contains(confKey)) { + return null; + } + return this.createAuthRequest(confKey).authorize(state); + } + + /** + * 根据回调信息获取登录用户的信息 + * + * @param confKey 配置的KEY,也即授权来源(如qq、weibo等) + * @param callback 接口回调信息 + * @return 授权成功后的用户信息,根据授权平台的不同,获取的数据完整性也不同 + */ + public AuthUser getAuthUser(String confKey, AuthCallback callback) { + if (!CONF_KEY_SET.contains(confKey)) { + return null; + } + AuthRequest authRequest = this.createAuthRequest(confKey); + // 根据返回的参数,执行登录请求(获取用户信息) + AuthResponse response = authRequest.login(callback); + // 判断结果 + if (response.ok()) { + return response.getData(); + } else { + return null; + } + } + + /** + * 根据具体地授权来源,获取授权请求工具类 + * + * @param confKey 配置的KEY,也即授权来源(如qq、weibo等) + * @return 授权工具类 + */ + public AuthRequest createAuthRequest(String confKey) { + if (!CONF_KEY_SET.contains(confKey)) { + throw new ServiceException("当前输入的配置KEY[" + confKey + "]不在许可范围内,请检查!"); + } + JustAuthBO authBO = this.getConfig(confKey); + AuthRequest authRequest; + switch (confKey) { + // QQ登录 + case "qq": + authRequest = new AuthQqRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .unionId(authBO.getUnionId()) + .build()); + break; + // 微博登录 + case "weibo": + authRequest = new AuthWeiboRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .build()); + break; + // 微信开放平台登录 + case "wechat_open": + authRequest = new AuthWeChatOpenRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .build()); + break; + // 微信公众号登录 + case "wechat_mp": + authRequest = new AuthWeChatMpRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .build()); + break; + // 微信企业号登录 + case "wechat_enterprise": + authRequest = new AuthWeChatEnterpriseQrcodeRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .agentId(authBO.getAgentId()) + .build()); + break; + // 百度登录 + case "baidu": + authRequest = new AuthBaiduRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .build()); + break; + // 钉钉登录 + case "dingtalk": + authRequest = new AuthDingTalkRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .build()); + break; + // 阿里云登录 + case "aliyun": + authRequest = new AuthAliyunRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .alipayPublicKey(authBO.getPublicKey()) + .build()); + break; + // 支付宝登录 + case "alipay": + authRequest = new AuthAlipayRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .alipayPublicKey(authBO.getPublicKey()) + .build()); + break; + // 华为登录 + case "huawei": + authRequest = new AuthHuaweiRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .build()); + break; + // 飞书登录 + case "feishu": + authRequest = new AuthFeishuRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .build()); + break; + // Gitee登录 + case "gitee": + authRequest = new AuthGiteeRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .scopes(AuthScopeUtils.getScopes(AuthGiteeScope.values())) + .build()); + break; + // GitHub登录 + case "github": + authRequest = new AuthGithubRequest(AuthConfig.builder() + .clientId(authBO.getAppID()) + .clientSecret(authBO.getAppSecret()) + .redirectUri(authBO.getRedirectUri()) + .build()); + break; + default: + throw new ServiceException("配置的KEY不存在,请检查!"); + } + return authRequest; + } + + /** + * 读取当前auth服务支持的KEY的集合 + * + * @return 支持的KEY的集合 + */ + public Set getConfKeySet() { + return CONF_KEY_SET; + } +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/oss/AliOSSProperties.java b/ss-component/src/main/java/com/zxdmy/excite/component/oss/AliOSSProperties.java new file mode 100644 index 0000000..9acd3f1 --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/oss/AliOSSProperties.java @@ -0,0 +1,16 @@ +package com.zxdmy.excite.component.oss; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "aliyun.oss") +public class AliOSSProperties { + private String endpoint; + private String accessKeyId; + private String accessKeySecret; + private String bucketName; + private String region; +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/oss/AliOSSUtils.java b/ss-component/src/main/java/com/zxdmy/excite/component/oss/AliOSSUtils.java new file mode 100644 index 0000000..5437675 --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/oss/AliOSSUtils.java @@ -0,0 +1,303 @@ +package com.zxdmy.excite.component.oss; + +import com.alibaba.fastjson.JSONObject; +import com.aliyun.oss.*; +import com.aliyun.oss.model.*; +import com.zxdmy.excite.common.exception.ServiceException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLDecoder; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +/** + * 阿里云 OSS 工具类 + */ + +@Component +public class AliOSSUtils{ + @Autowired//将OSS的配置注入进来,后面需要用到 + private AliOSSProperties aliOSSProperties; + @Resource + protected HttpServletRequest request; + + + + /** + * oss文件下载 + * @param path 文件下载本地地址 + * @param pathOss oss地址 + * @return + * @throws IOException + */ + public Boolean download(String path,String pathOss) throws IOException { + + //获取阿里云OSS参数 + String endpoint = aliOSSProperties.getEndpoint(); + String accessKeyId = aliOSSProperties.getAccessKeyId(); + String accessKeySecret = aliOSSProperties.getAccessKeySecret(); + String bucketName = aliOSSProperties.getBucketName(); + + // 创建连接 + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret); +// content-disposition + try { + // 下载Object到本地文件,并保存到指定的本地路径中。如果指定的本地文件存在会覆盖,不存在则新建。 + // 如果未指定本地路径,则下载后的文件默认保存到示例程序所属项目对应本地路径中。 + ossClient.getObject(new GetObjectRequest(bucketName, pathOss), new File(path)); + } catch (OSSException oe) { + System.out.println("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + System.out.println("Error Message:" + oe.getErrorMessage()); + System.out.println("Error Code:" + oe.getErrorCode()); + System.out.println("Request ID:" + oe.getRequestId()); + System.out.println("Host ID:" + oe.getHostId()); + } catch (ClientException ce) { + System.out.println("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + System.out.println("Error Message:" + ce.getMessage()); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + return false; + + } + + /** + * 删除oss文件 + * @param path 文件地址 + * @return + * @throws IOException + */ + public Boolean delete(String path) throws IOException { + + //获取阿里云OSS参数 + String endpoint = aliOSSProperties.getEndpoint(); + String accessKeyId = aliOSSProperties.getAccessKeyId(); + String accessKeySecret = aliOSSProperties.getAccessKeySecret(); + String bucketName = aliOSSProperties.getBucketName(); + + // 创建连接 + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret); + + try { + // 删除文件。 + // 文件完整路径中不能包含Bucket名称。 + List keys = new ArrayList(); + keys.add(path); + + DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(keys).withEncodingType("url")); + List deletedObjects = deleteObjectsResult.getDeletedObjects(); + try { + for(String obj : deletedObjects) { + String deleteObj = URLDecoder.decode(obj, "UTF-8"); + System.out.println(deleteObj); + return !(ossClient.doesObjectExist(bucketName,path)); + } + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } catch (OSSException oe) { + System.out.println("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + System.out.println("Error Message:" + oe.getErrorMessage()); + System.out.println("Error Code:" + oe.getErrorCode()); + System.out.println("Request ID:" + oe.getRequestId()); + System.out.println("Host ID:" + oe.getHostId()); + } catch (ClientException ce) { + System.out.println("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + System.out.println("Error Message:" + ce.getMessage()); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + return false; + + } + + /** + * 查找oss文件 + * @param path 文件地址 + * @return + * @throws IOException + */ + public Boolean query(String path) throws IOException { + + //获取阿里云OSS参数 + String endpoint = aliOSSProperties.getEndpoint(); + String accessKeyId = aliOSSProperties.getAccessKeyId(); + String accessKeySecret = aliOSSProperties.getAccessKeySecret(); + String bucketName = aliOSSProperties.getBucketName(); + + // 创建连接 + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret); + + try { + // 判断文件是否存在。如果返回值为true,则文件存在,否则存储空间或者文件不存在。 + // 设置是否进行重定向或者镜像回源。默认值为true,表示忽略302重定向和镜像回源;如果设置isINoss为false,则进行302重定向或者镜像回源。 + //boolean isINoss = true; + boolean found = ossClient.doesObjectExist(bucketName, path); + //boolean found = ossClient.doesObjectExist(bucketName, objectName, isINoss); + return found; + } catch (OSSException oe) { + System.out.println("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + System.out.println("Error Message:" + oe.getErrorMessage()); + System.out.println("Error Code:" + oe.getErrorCode()); + System.out.println("Request ID:" + oe.getRequestId()); + System.out.println("Host ID:" + oe.getHostId()); + } catch (ClientException ce) { + System.out.println("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + System.out.println("Error Message:" + ce.getMessage()); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + return false; + } + + /** + * 拷贝oss地址文件位置至其他oss地址位置(源Bucket相同) + * @param path + * @param newPath + * @return + * @throws IOException + */ + public Boolean copy(String path,String newPath) throws IOException { + + //获取阿里云OSS参数 + String endpoint = aliOSSProperties.getEndpoint(); + String accessKeyId = aliOSSProperties.getAccessKeyId(); + String accessKeySecret = aliOSSProperties.getAccessKeySecret(); + String bucketName = aliOSSProperties.getBucketName(); + String newBucketName = aliOSSProperties.getBucketName(); + + // 创建连接 + OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret); + + try { + + ObjectMetadata objectMetadata = ossClient.getObjectMetadata(bucketName, path); + // 获取被拷贝文件的大小。 + long contentLength = objectMetadata.getContentLength(); + long gb = 1024 * 1024 * 1024; + //小文件上传 + if(contentLength < gb) { + // 拷贝文件。 + CopyObjectResult result = ossClient.copyObject(bucketName, path, newBucketName, newPath); + System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified()); + // 判断文件是否存在。如果返回值为true,则文件存在,否则存储空间或者文件不存在。 + // 设置是否进行重定向或者镜像回源。默认值为true,表示忽略302重定向和镜像回源;如果设置isINoss为false,则进行302重定向或者镜像回源。 + + } + //大文件上传(分片上传[大于1GB]) + else { + // 设置分片大小为10 MB。单位为字节。 + long partSize = 1024 * 1024 * 10; + + // 计算分片总数。 + int partCount = (int) (contentLength / partSize); + if (contentLength % partSize != 0) { + partCount++; + } + System.out.println("total part count:" + partCount); + + // 初始化拷贝任务。可以通过InitiateMultipartUploadRequest指定目标文件元信息。 + InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(newBucketName, newPath); + // 拷贝源文件ContentType和UserMetadata,分片拷贝默认不拷贝源文件的ContentType和UserMetadata。 + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(objectMetadata.getContentType()); + metadata.setUserMetadata(objectMetadata.getUserMetadata()); + initiateMultipartUploadRequest.setObjectMetadata(metadata); + InitiateMultipartUploadResult initiateMultipartUploadResult = ossClient.initiateMultipartUpload(initiateMultipartUploadRequest); + String uploadId = initiateMultipartUploadResult.getUploadId(); + + // 分片拷贝。 + List partETags = new ArrayList(); + for (int i = 0; i < partCount; i++) { + // 计算每个分片的大小。 + long skipBytes = partSize * i; + long size = Math.min(partSize, contentLength - skipBytes); + + // 创建UploadPartCopyRequest。可以通过UploadPartCopyRequest指定限定条件。 + UploadPartCopyRequest uploadPartCopyRequest = + new UploadPartCopyRequest(bucketName, path, newBucketName, newPath); + uploadPartCopyRequest.setUploadId(uploadId); + uploadPartCopyRequest.setPartSize(size); + uploadPartCopyRequest.setBeginIndex(skipBytes); + uploadPartCopyRequest.setPartNumber(i + 1); + //Map headers = new HashMap(); + // 指定拷贝的源地址。 + // headers.put(OSSHeaders.COPY_OBJECT_SOURCE, "/examplebucket/desexampleobject.txt"); + // 指定源Object的拷贝范围。例如设置bytes=0~1023,表示拷贝1~1024字节的内容。 + // headers.put(OSSHeaders.COPY_SOURCE_RANGE, "bytes=0~1023"); + // 如果源Object的ETag值和您提供的ETag相等,则执行拷贝操作,并返回200 OK。 + // headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_MATCH, "5B3C1A2E053D763E1B002CC607C5****"); + // 如果源Object的ETag值和您提供的ETag不相等,则执行拷贝操作,并返回200 OK。 + // headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_NONE_MATCH, "5B3C1A2E053D763E1B002CC607C5****"); + // 如果指定的时间等于或者晚于文件实际修改时间,则正常拷贝文件,并返回200 OK。 + // headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_UNMODIFIED_SINCE, "2021-12-09T07:01:56.000Z"); + // 如果源Object在用户指定的时间以后被修改过,则执行拷贝操作。 + // headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_MODIFIED_SINCE, "2021-12-09T07:01:56.000Z"); + // uploadPartCopyRequest.setHeaders(headers); + UploadPartCopyResult uploadPartCopyResult = ossClient.uploadPartCopy(uploadPartCopyRequest); + + // 将返回的分片ETag保存到partETags中。 + partETags.add(uploadPartCopyResult.getPartETag()); + } + + // 提交分片拷贝任务。 + CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest( + newBucketName, newPath, uploadId, partETags); + ossClient.completeMultipartUpload(completeMultipartUploadRequest); + } + + boolean found = ossClient.doesObjectExist(newBucketName, newPath); + return found; + } catch (OSSException oe) { + System.out.println("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + System.out.println("Error Message:" + oe.getErrorMessage()); + System.out.println("Error Code:" + oe.getErrorCode()); + System.out.println("Request ID:" + oe.getRequestId()); + System.out.println("Host ID:" + oe.getHostId()); + } catch (ClientException ce) { + System.out.println("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + System.out.println("Error Message:" + ce.getMessage()); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + return false; + } + + + +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/oss/OSSVO.java b/ss-component/src/main/java/com/zxdmy/excite/component/oss/OSSVO.java new file mode 100644 index 0000000..37e3cef --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/oss/OSSVO.java @@ -0,0 +1,18 @@ +package com.zxdmy.excite.component.oss; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class OSSVO { + + private String region; + private String accessKeyId; + private String accessKeySecret; + private String bucketName; + private String endpoint; + + private String fileName; + private String prefix; +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/qiniu/QiniuOssService.java b/ss-component/src/main/java/com/zxdmy/excite/component/qiniu/QiniuOssService.java new file mode 100644 index 0000000..f91a9fe --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/qiniu/QiniuOssService.java @@ -0,0 +1,428 @@ +package com.zxdmy.excite.component.qiniu; + +import cn.hutool.core.util.DesensitizedUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.qiniu.common.QiniuException; +import com.qiniu.http.Response; +import com.qiniu.storage.*; +import com.qiniu.storage.model.FetchRet; +import com.qiniu.storage.model.FileInfo; +import com.qiniu.util.Auth; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.common.service.IGlobalConfigService; +import com.zxdmy.excite.component.vo.QiniuFileVO; +import com.zxdmy.excite.component.bo.QiniuOssBO; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +/** + * 七牛云对象存储服务实现类 + * 更多接口,可以根据 https://developer.qiniu.com/kodo/1239/java 实现。 + * + * @author 沈松 + * @since 2022-01-02 0002 23:33 + */ +@Service +@AllArgsConstructor +public class QiniuOssService { + + IGlobalConfigService configService; + + private static final String DEFAULT_SERVICE = "qiniu"; + private static final String DEFAULT_KEY = "qiniuOss"; + + /** + * 将七牛云的信息保存至数据库 + * + * @param qiniuOssBO 七牛云信息实体。如果指定key,则存储的配置信息的key即为所指定 + * @return 结果 + */ + public boolean saveQiniuConfig(QiniuOssBO qiniuOssBO) { + // 如果必填信息为空,则返回错误 + if (null == qiniuOssBO.getSecretKey() || null == qiniuOssBO.getAccessKey() || null == qiniuOssBO.getBucket() || null == qiniuOssBO.getDomain()) { + throw new ServiceException("AK、SK、空间名称或者域名为空,请核实!"); + } + // 核实无误,填充数据 + if (null == qiniuOssBO.getProtocol()) { + qiniuOssBO.setProtocol("http"); + } + try { + if (null == qiniuOssBO.getKey()) { + return configService.save(DEFAULT_SERVICE, DEFAULT_KEY, qiniuOssBO, true); + } + return configService.save(DEFAULT_SERVICE, qiniuOssBO.getKey(), qiniuOssBO, true); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } + + /** + * 从数据库读取七牛云配置信息(指定key) + * + * @param confKey 配置文件的key,不同的key对应不同的存储空间 + * @return 七牛云配置信息实体 + */ + public QiniuOssBO getQiniuConfig(String confKey) { + QiniuOssBO qiniuOssBO = new QiniuOssBO(); + qiniuOssBO = (QiniuOssBO) configService.get(DEFAULT_SERVICE, confKey, qiniuOssBO); + return qiniuOssBO; + } + + /** + * 从数据库读取七牛云配置信息(默认key) + * + * @return 七牛云配置信息实体 + */ + public QiniuOssBO getQiniuConfig() { + return this.getQiniuConfig(DEFAULT_KEY); + } + + /** + * 从数据库读取七牛云配置信息,并脱敏(指定key) + * + * @param confKey 配置文件的key,不同的key对应不同的存储空间 + * @return 七牛云配置信息实体 + */ + public QiniuOssBO getQiniuConfigHide(String confKey) { + QiniuOssBO qiniuOssBO = new QiniuOssBO(); + qiniuOssBO = (QiniuOssBO) configService.get(DEFAULT_SERVICE, confKey, qiniuOssBO); + qiniuOssBO.setAccessKey(DesensitizedUtil.idCardNum(qiniuOssBO.getAccessKey(), 2, 2)); + qiniuOssBO.setSecretKey(DesensitizedUtil.idCardNum(qiniuOssBO.getSecretKey(), 2, 2)); + return qiniuOssBO; + } + + /** + * 从数据库读取七牛云配置信息,并脱敏(默认key) + * + * @return 七牛云配置信息实体 + */ + public QiniuOssBO getQiniuConfigHide() { + return this.getQiniuConfigHide(DEFAULT_KEY); + } + + /** + * 获取全部的七牛云配置信息 + * + * @param desensitized 是否脱敏:true:脱敏, false:不脱敏 + * @return 读取全部配置信息 + */ + public List getQiniuConfigList(Boolean desensitized) { + QiniuOssBO qiniuOssBO = new QiniuOssBO(); + List objectList = configService.getList(DEFAULT_SERVICE, qiniuOssBO); + ObjectMapper objectMapper = new ObjectMapper(); + List qiniuOssBOList = new ArrayList<>(); + for (Object o : objectList) { + qiniuOssBO = objectMapper.convertValue(o, qiniuOssBO.getClass()); + if (desensitized) { + qiniuOssBO.setAccessKey(DesensitizedUtil.idCardNum(qiniuOssBO.getAccessKey(), 2, 2)); + qiniuOssBO.setSecretKey(DesensitizedUtil.idCardNum(qiniuOssBO.getSecretKey(), 2, 2)); + } + qiniuOssBOList.add(qiniuOssBO); + } + return qiniuOssBOList; + } + + /** + * 生成上传的Token(指定key) + * + * @param confKey 配置文件的key,不同的key对应不同的存储空间 + * @param fileKey 文件的key,又称文件名,可以带路径 + * @param expireSeconds 过期时间 + * @return 结果 + */ + public QiniuOssBO createUploadToken(String confKey, String fileKey, Long expireSeconds) { + // 如果必填信息为空,则返回 + if (null == fileKey || "".equals(fileKey)) { + throw new ServiceException("文件的key为空,请核实!"); + } + // 读取配置信息 + QiniuOssBO qiniuOssBO = new QiniuOssBO(); + qiniuOssBO = (QiniuOssBO) configService.get(DEFAULT_SERVICE, confKey, qiniuOssBO); + // 生成Token + Auth auth = Auth.create(qiniuOssBO.getAccessKey(), qiniuOssBO.getSecretKey()); + String upToken = auth.uploadToken(qiniuOssBO.getBucket(), fileKey, expireSeconds, null); + // 写入Token,并返回 + qiniuOssBO.setUploadToken(upToken); + return qiniuOssBO; + } + + /** + * 生成上传的Token(默认key) + * + * @param fileKey 文件的key,又称文件名 + * @param expireSeconds 过期时间 + * @return 结果 + */ + public QiniuOssBO createUploadToken(String fileKey, Long expireSeconds) { + return this.createUploadToken(DEFAULT_KEY, fileKey, expireSeconds); + } + + /** + * 后端上传文件(指定key) + * + * @param confKey 配置文件的key,不同的key对应不同的存储空间 + * @param file 文件 + * @return 结果 + */ + public QiniuFileVO uploadFile(String confKey, File file) { + if (null == file) { + throw new ServiceException("上传的文件为空,请检查!"); + } + // 生成Token + QiniuOssBO qiniuOssBO = this.createUploadToken(confKey, file.getName(), 3600L); + // 配置信息 + Configuration configuration = new Configuration(this.createRegion(qiniuOssBO.getRegion())); + // 构造上传管理类 + UploadManager uploadManager = new UploadManager(configuration); + // 进行上传 + try { + Response response = uploadManager.put(file, file.getName(), qiniuOssBO.getUploadToken()); + if (response.isOK()) { + return new QiniuFileVO() + .setProtocol(qiniuOssBO.getProtocol()) + .setDomain(qiniuOssBO.getDomain()) + .setKey(qiniuOssBO.getKey()); + } + return null; + } catch (QiniuException ex) { + throw new ServiceException(ex.response.toString()); + } + } + + /** + * 后端上传文件(默认key) + * + * @param file 文件 + * @return 七牛云配置信息实体 + */ + public QiniuFileVO uploadFile(File file) { + return this.uploadFile(DEFAULT_KEY, file); + } + + /** + * 抓取网络资源到空间(指定key) + * + * @param confKey 配置文件的key,不同的key对应不同的存储空间 + * @param fileKey 文件名 + * @param remoteSrcUrl 远程链接 + * @return 文件信息 + */ + public QiniuFileVO uploadFileFromUrl(String confKey, String fileKey, String remoteSrcUrl) { + QiniuOssBO qiniuOssBO = this.getQiniuConfig(confKey); + if (qiniuOssBO == null) { + throw new ServiceException("key为[" + confKey + "]的配置信息为空,请检查!"); + } + BucketManager bucketManager = this.createBucketManager(qiniuOssBO); + //抓取网络资源到空间 + try { + FetchRet fetchRet = bucketManager.fetch(remoteSrcUrl, qiniuOssBO.getBucket(), fileKey); + return new QiniuFileVO() + .setProtocol(qiniuOssBO.getProtocol()) + .setDomain(qiniuOssBO.getDomain()) + .setKey(fetchRet.key) + .setHash(fetchRet.hash) + .setMimeType(fetchRet.mimeType) + .setSize(fetchRet.fsize); + } catch (QiniuException ex) { + throw new ServiceException(ex.response.toString()); + } + } + + /** + * 抓取网络资源到空间(默认KEY) + * + * @param fileKey 文件名 + * @param remoteSrcUrl 远程链接 + * @return 文件信息 + */ + public QiniuFileVO uploadFileFromUrl(String fileKey, String remoteSrcUrl) { + return this.uploadFileFromUrl(DEFAULT_KEY, fileKey, remoteSrcUrl); + } + + /** + * 获取七牛云空间的全部文件(指定key) + * + * @param confKey 配置文件的key,不同的key对应不同的存储空间 + * @param prefix 文件前缀 + * @param delimiter 文件分隔符 + * @return 文件信息列表 + */ + public List getQiniuFileListAll(String confKey, String prefix, String delimiter) { + QiniuOssBO qiniuOssBO = this.getQiniuConfig(confKey); + if (qiniuOssBO == null) { + throw new ServiceException("key为[" + confKey + "]的配置信息为空,请检查!"); + } + BucketManager bucketManager = this.createBucketManager(qiniuOssBO); + BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(qiniuOssBO.getBucket(), prefix, 1000, delimiter); + // 记录返回值 + List fileInfoList = new ArrayList<>(); + while (fileListIterator.hasNext()) { + fileInfoList.addAll(Arrays.asList(fileListIterator.next())); + } + return fileInfoList; + } + + /** + * 获取七牛云空间的全部文件(默认key) + * + * @param prefix 文件前缀 + * @param delimiter 文件分隔符 + * @return 文件信息列表 + */ + public List getQiniuFileListAll(String prefix, String delimiter) { + return this.getQiniuFileListAll(DEFAULT_KEY, prefix, delimiter); + } + + /** + * 获取七牛云空间的分页文件列表(分页),如果页数超限,则返回第一页(指定key) + * + * @param confKey 配置文件的key,不同的key对应不同的存储空间 + * @param page 页号 + * @param limit 每页条数 + * @param prefix 前缀 + * @param delimiter 分隔符 + * @return 页面类Page + */ + public Page getQiniuFileListPage(String confKey, Integer page, Integer limit, String prefix, String delimiter) { + // 定义返回Page实体 + Page fileInfoPage = new Page<>(); + // 获取配置 + QiniuOssBO qiniuOssBO = this.getQiniuConfig(confKey); + if (qiniuOssBO == null) { + throw new ServiceException("key为[" + confKey + "]的配置信息为空,请检查!"); + } + // 生成管理器 + BucketManager bucketManager = this.createBucketManager(qiniuOssBO); + // 获取列表迭代器 + BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(qiniuOssBO.getBucket(), prefix, limit, delimiter); + // 遍历直至找到指定页数 + long total = 0; + while (fileListIterator.hasNext()) { + page--; + if (page == 0) { + FileInfo[] items = fileListIterator.next(); + fileInfoPage.setRecords(Arrays.asList(items)); + total += items.length; + } else { + total += fileListIterator.next().length; + } + } + if (fileInfoPage.getRecords().size() == 0) { + fileInfoPage.setRecords(Arrays.asList(fileListIterator.next())); + } + fileInfoPage.setCurrent(page).setSize(limit).setTotal(total); + return fileInfoPage; + } + + /** + * 获取七牛云空间的分页文件列表(分页),如果页数超限,则返回第一页(默认key) + * + * @param page 页号 + * @param limit 每页条数 + * @param prefix 前缀 + * @param delimiter 分隔符 + * @return 页面类Page + */ + public Page getQiniuFileListPage(Integer page, Integer limit, String prefix, String delimiter) { + return this.getQiniuFileListPage(DEFAULT_KEY, page, limit, prefix, delimiter); + } + + /** + * 获取下载链接(一般针对私有资源使用)(指定key) + * + * @param confKey 配置文件的key,不同的key对应不同的存储空间 + * @param fileKey 下载资源在七牛云存储的key + * @param attName 下载文件的名字。null:与存储的文件名相同 + * @param expireSeconds 有效期(秒),一般取3600(即1小时) + * @return 下载链接 + */ + public String getDownloadUrl(String confKey, String fileKey, String attName, Long expireSeconds) { + // 获取配置 + QiniuOssBO qiniuOssBO = this.getQiniuConfig(confKey); + if (qiniuOssBO == null) { + throw new ServiceException("key为[" + confKey + "]的配置信息为空,请检查!"); + } + DownloadUrl url = new DownloadUrl(qiniuOssBO.getDomain(), "https".equals(qiniuOssBO.getProtocol()), fileKey); + if (null != attName) { + url.setAttname(attName); + } + Auth auth = Auth.create(qiniuOssBO.getAccessKey(), qiniuOssBO.getSecretKey()); + long deadline = expireSeconds + new Date().getTime(); + String downloadUrl = ""; + try { + downloadUrl = url.buildURL(auth, deadline); + } catch (QiniuException e) { + throw new ServiceException(e.response.toString()); + } + return downloadUrl; + } + + /** + * 获取下载链接(一般针对私有资源使用)(默认key) + * + * @param fileKey 下载资源在七牛云存储的key + * @param attName 下载文件的名字。null:与存储的文件名相同 + * @param expireSeconds 有效期(秒),一般取3600(即1小时) + * @return 下载链接 + */ + public String getDownloadUrl(String fileKey, String attName, Long expireSeconds) { + return this.getDownloadUrl(DEFAULT_KEY, fileKey, attName, expireSeconds); + } + + /** + * 根据配置信息生成空间管理器 + * + * @param qiniuOssBO 配置信息 + * @return 空间管理器 + */ + private BucketManager createBucketManager(QiniuOssBO qiniuOssBO) { + // 生成Auth授权类 + Auth auth = Auth.create(qiniuOssBO.getAccessKey(), qiniuOssBO.getSecretKey()); + // 配置信息, + Configuration configuration = new Configuration(this.createRegion(qiniuOssBO.getRegion())); + // 返回 + return new BucketManager(auth, configuration); + } + + /** + * 根据空间地址设置Region + * 详情:https://developer.qiniu.com/kodo/1671/region-endpoint-fq + * + * @param re 空间地域:华东:z0; 华北:z1; 华南:z2; 北美:na0; 东南亚:as0; 华东-浙江2:cn-east-2 + * @return 地域类 + */ + private Region createRegion(String re) { + // 设置区域:如果不为空 + Region region; + switch (re) { + case "z0": + region = Region.huadong(); + break; + case "z1": + region = Region.huabei(); + break; + case "z2": + region = Region.huanan(); + break; + case "na0": + region = Region.beimei(); + break; + case "as0": + region = Region.xinjiapo(); + break; + case "cn-east-2": + region = Region.huadongZheJiang2(); + break; + default: + region = new Region.Builder().autoRegion("https://uc.qbox.me"); + } + return region; + } +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/vo/AliyunOssPolicyVO.java b/ss-component/src/main/java/com/zxdmy/excite/component/vo/AliyunOssPolicyVO.java new file mode 100644 index 0000000..7808f80 --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/vo/AliyunOssPolicyVO.java @@ -0,0 +1,56 @@ +package com.zxdmy.excite.component.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 此[表现层对象]用来返回前端上传时,需要用到的各种参数。 + * 应用场景:后端生成Policy,前端直传阿里云OSS。上传最大值:5G。 + * 参考资料: + * https://help.aliyun.com/document_detail/31927.htm + * https://help.aliyun.com/document_detail/31926.htm + * + * @author 沈松 + * @since 2022/1/5 21:06 + */ +@Data +@Accessors(chain = true) +public class AliyunOssPolicyVO implements Serializable { + + /*** + * Bucket域名,即Endpoint访问域名。格式为:https://{bucketName}.{endpoint},如:https://bucket-name.oss-cn-hangzhou.aliyuncs.com + */ + private String host; + + /** + * 文件完整名(如果有前缀则需要携带),如:hello.zip,user/10001/hello.rar + */ + private String key; + + /** + * 用户表单上传的策略(Policy),Policy为经过Base64编码过的字符串。详情请参见 https://help.aliyun.com/document_detail/31988.htm?spm=a2c4g.11186623.0.0.69de5458ikCoa2#section-d5z-1ww-wdb + */ + private String policy; + + /** + * 用户请求的AccessKey ID。 + */ + private String accessKeyId; + + /** + * 设置阿里云OSS服务端返回状态码为200,不设置则默认返回状态码204。 + */ + private final String success_action_status = "200"; + + /** + * 上传后的阿里云OSS服务器回调功能。即上传完成后,阿里云向此地址发送一个回调。如果不涉及上传回调,请不要填充值。 + */ + private String callback; + + /** + * 对Policy签名后的字符串。详情请参见:https://help.aliyun.com/document_detail/31988.htm?spm=a2c4g.11186623.0.0.69de5458ikCoa2#section-wny-mww-wdb + */ + private String signature; +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/vo/QiniuFileVO.java b/ss-component/src/main/java/com/zxdmy/excite/component/vo/QiniuFileVO.java new file mode 100644 index 0000000..59ab1be --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/vo/QiniuFileVO.java @@ -0,0 +1,71 @@ +package com.zxdmy.excite.component.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + *

                          + * 描述 + *

                          + * + * @author 沈松 + * @since 2022/1/4 11:51 + */ +@Data +@Accessors(chain = true) +public class QiniuFileVO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 文件名 + */ + public String key; + + /** + * 文件hash值 + */ + public String hash; + + /** + * 文件的md5值 + */ + public String md5; + + /** + * 文件大小,单位:字节 + */ + public long size; + + /** + * 文件上传时间,单位为:100纳秒 + */ + public long putTime; + + /** + * 文件的mimeType + */ + public String mimeType; + + /** + * 文件的状态,0表示启用,1表示禁用 + */ + public int status; + + /** + * 七牛云该空间(bucket)绑定的CDN加速域名 + */ + private String domain; + + /** + * 七牛云该空间(bucket)绑定的CDN加速域名的协议 http | https + */ + private String protocol; + + /* + * 上传Token + */ + private String uploadToken; +} diff --git a/ss-component/src/main/java/com/zxdmy/excite/component/wechat/WeChatPayService.java b/ss-component/src/main/java/com/zxdmy/excite/component/wechat/WeChatPayService.java new file mode 100644 index 0000000..94fa19c --- /dev/null +++ b/ss-component/src/main/java/com/zxdmy/excite/component/wechat/WeChatPayService.java @@ -0,0 +1,245 @@ +package com.zxdmy.excite.component.wechat; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; +import com.github.binarywang.wxpay.bean.result.*; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.common.service.IGlobalConfigService; +import com.zxdmy.excite.common.utils.HttpServletRequestUtil; +import com.zxdmy.excite.component.bo.WeChatPayBO; +import lombok.AllArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 微信支付服务实现类 + * 只实现V3版本的接口(文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/index.shtml ) + * + * @author 沈松 + * @since 2022-01-02 0002 23:34 + */ +@Service +@AllArgsConstructor +public class WeChatPayService { + + private IGlobalConfigService configService; + + private static final String DEFAULT_SERVICE = "wechatPay"; + + private static final String DEFAULT_KEY = "wechatPay"; + + // 千万不要使用这个垃圾的微信支付沙盒环境..... + private static final Boolean SAND_BOX_ENV = false; + + /** + * 保存微信支付配置信息至数据库 + * + * @param weChatPayBO 微信支付实体 + * @return 结果:T|F + * @throws JsonProcessingException 异常 + */ + public boolean saveConfig(WeChatPayBO weChatPayBO) throws JsonProcessingException { + // 必填信息不能为空 + if (null == weChatPayBO.getAppId() || null == weChatPayBO.getMchId() || null == weChatPayBO.getMchKey()) { + throw new ServiceException("APPID、商户号、商户秘钥不能为空!"); + } + // 保存并返回结果 + return configService.save(DEFAULT_SERVICE, null != weChatPayBO.getKey() ? weChatPayBO.getKey() : DEFAULT_KEY, weChatPayBO, true); + } + + /** + * 从数据库中读取配置信息 + * + * @param confKey 微信支付的配置KEY + * @return 微信支付配置信息 + */ + public WeChatPayBO getConfig(String confKey) { + if (null == confKey) { + return this.getConfig(); + } + return (WeChatPayBO) configService.get(DEFAULT_SERVICE, confKey, new WeChatPayBO()); + } + + /** + * 从数据库中读取配置信息(默认KEY) + * + * @return 微信支付配置信息 + */ + public WeChatPayBO getConfig() { + return this.getConfig(DEFAULT_KEY); + } + + /** + * 下单接口(只设置了必填信息)(V3版本) + * + * @param confKey 必填:微信支付配置信息的KEY。如果使用默认KEY,输入null + * @param tradeType 必填:交易类型:jsapi(含小程序)、app、h5、native + * @param description 必填:商品描述(商品标题) + * @param outTradeNo 必填:商家订单号 + * @param total 必填:商品金额(单位:分) + * @param openId 特殊必填:支付用户的OpenId,JSAPI支付时必填。 + * @return 支付返回结果:
                          APP支付、JSAPI支付为[预支付交易会话标识]
                          Native支付为[二维码链接]
                          H5支付为[支付跳转链接] + */ + public String pay(String confKey, String tradeType, String description, String outTradeNo, Integer total, String openId) { + // 构建统一下单请求参数对象 + WxPayUnifiedOrderV3Request wxPayUnifiedOrderV3Request = new WxPayUnifiedOrderV3Request(); + // 对象中写入数据 + wxPayUnifiedOrderV3Request + // 【1】必填信息 + // 应用ID:必填,可不填,通过配置信息读取 + // .setAppid(weChatPayBO.getAppId()) + // 直连商户号:必填,可不填,通过配置信息读取 + // .setMchid(weChatPayBO.getMchId()) + // 商品描述:必填 + .setDescription(description) + // 商户订单号:必填,同一个商户号下唯一 + .setOutTradeNo(outTradeNo) + // 通知地址:必填,公网域名必须为https,外网可访问。 + // 可不填,通过配置信息读取 + .setNotifyUrl(this.getConfig(confKey).getNotifyUrl()) + // 订单金额:单位(分) + .setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(total)) + // 【2】选填信息 + // 附加信息 + .setAttach("附加信息") + // 订单优惠标记 + .setGoodsTag("ABCD") + // ... + ; + + try { + // 根据请求类型,返回指定类型,其中包含:【3】条件必填信息 + switch (tradeType.toLowerCase()) { + // Native支付 + case "native": + return this.getWxPayService(confKey).unifiedOrderV3(TradeTypeEnum.NATIVE, wxPayUnifiedOrderV3Request).getCodeUrl(); + // JSAPI支付 + case "jsapi": + // 用户在直连商户appid下的唯一标识。 下单前需获取到用户的Openid + wxPayUnifiedOrderV3Request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(openId)); + return this.getWxPayService(confKey).unifiedOrderV3(TradeTypeEnum.JSAPI, wxPayUnifiedOrderV3Request).getPrepayId(); + // H5支付 + case "h5": + wxPayUnifiedOrderV3Request.setSceneInfo( + new WxPayUnifiedOrderV3Request.SceneInfo() + // 用户终端IP + .setPayerClientIp(HttpServletRequestUtil.getRemoteIP()) + .setH5Info( + new WxPayUnifiedOrderV3Request.H5Info() + // 场景类型 + .setType("wechat") + ) + ); + return this.getWxPayService(confKey).unifiedOrderV3(TradeTypeEnum.H5, wxPayUnifiedOrderV3Request).getH5Url(); + // APP支付 + case "app": + return this.getWxPayService(confKey).unifiedOrderV3(TradeTypeEnum.APP, wxPayUnifiedOrderV3Request).getPrepayId(); + default: + throw new ServiceException("输入的[" + tradeType + "]不合法,只能为native、jsapi、h5、app其一,请核实!"); + } + } catch (WxPayException e) { + throw new ServiceException(e.getMessage()); + } + } + + /** + * 订单查询接口(新版V3) + * + * @param confKey 必填:微信支付配置信息的KEY。如果使用默认KEY,输入null + * @param transactionId 微信订单号 + * @param outTradeNo 商户系统内部的订单号,当没提供transactionId时需要传这个。 + * @return 查询订单 返回结果对象 + */ + public WxPayOrderQueryV3Result query(String confKey, String transactionId, String outTradeNo) { + try { + return this.getWxPayService(confKey).queryOrderV3(transactionId, outTradeNo); + } catch (WxPayException e) { + throw new ServiceException(e.getMessage()); + } + } + + /** + * 退款接口 + * + * @param confKey 必填:微信支付配置信息的KEY。如果使用默认KEY,输入null + * @param outTradeNo 商户订单号 + * @param outRefundNo 商户退款单号 + * @param total 订单总金额(单位:分) + * @param refund 退款金额(单位:分) + */ + public WxPayRefundV3Result refund(String confKey, String outTradeNo, String outRefundNo, int total, int refund) { + WxPayRefundV3Request wxPayRefundV3Request = new WxPayRefundV3Request(); + wxPayRefundV3Request + .setOutTradeNo(outTradeNo) + .setOutRefundNo(outRefundNo) + .setAmount(new WxPayRefundV3Request.Amount() + .setTotal(total) + .setRefund(refund) + .setCurrency("CNY") + ); + try { + return this.getWxPayService(confKey).refundV3(wxPayRefundV3Request); + } catch (WxPayException e) { + throw new ServiceException(e.getMessage()); + } + } + + /** + * 获取微信支付相关接口的服务 + * (后续的几个服务方法,实现了基本的实例) + * (此接口也可以直接在controller中使用) + * + * @return 微信支付服务接口 + */ + public WxPayService getWxPayService(String confKey) { + if (null == confKey) { + return this.getWxPayService(); + } + // 读取配置信息 + WeChatPayBO weChatPayBO = this.getConfig(confKey); + // 生成配置 + WxPayConfig payConfig = new WxPayConfig(); + // 填充基本配置信息 + payConfig.setAppId(StringUtils.trimToNull(weChatPayBO.getAppId())); + payConfig.setMchId(StringUtils.trimToNull(weChatPayBO.getMchId())); + payConfig.setMchKey(StringUtils.trimToNull(weChatPayBO.getMchKey())); + payConfig.setApiV3Key(StringUtils.trimToNull(weChatPayBO.getApiV3Key())); + payConfig.setSubAppId(StringUtils.trimToNull(weChatPayBO.getSubAppId())); + payConfig.setSubMchId(StringUtils.trimToNull(weChatPayBO.getSubMchId())); + payConfig.setKeyPath(StringUtils.trimToNull(weChatPayBO.getKeyPath())); + payConfig.setPrivateCertPath(StringUtils.trimToNull(weChatPayBO.getPrivateCertPath())); + payConfig.setPrivateKeyPath(StringUtils.trimToNull(weChatPayBO.getPrivateKeyPath())); + payConfig.setNotifyUrl(StringUtils.trimToNull(weChatPayBO.getNotifyUrl())); + // 创建配置服务 + WxPayService wxPayService = new WxPayServiceImpl(); + wxPayService.setConfig(payConfig); + // 可以指定是否使用沙箱环境 + payConfig.setUseSandboxEnv(SAND_BOX_ENV); + if (SAND_BOX_ENV) { + try { + payConfig.setMchKey(wxPayService.getSandboxSignKey()); + wxPayService.setConfig(payConfig); + } catch (WxPayException e) { + throw new ServiceException(e.getMessage()); + } + } + // 返回结果 + return wxPayService; + } + + /** + * 获取微信支付相关接口的服务(默认KEY) + * + * @return 微信支付服务接口 + */ + public WxPayService getWxPayService() { + return this.getWxPayService(DEFAULT_KEY); + } + +} diff --git a/ss-framework/README.md b/ss-framework/README.md new file mode 100644 index 0000000..560f1ee --- /dev/null +++ b/ss-framework/README.md @@ -0,0 +1,3 @@ +# ExciteFramework 模块 + +系统框架模块,主要实现与系统架构相关的功能,如权限认证等。 \ No newline at end of file diff --git a/ss-framework/pom.xml b/ss-framework/pom.xml new file mode 100644 index 0000000..ac3dbc0 --- /dev/null +++ b/ss-framework/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + com.zxdmy.excite + shensong + 2.0.0 + + + ss-framework + 2.0.0 + ss-framework + + 描述信息. + + + + + + com.zxdmy.excite + ss-system + 2.0.0 + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + com.github.oshi + oshi-core + 6.1.0 + + + + + + diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/aop/AnnotationSaveLoginLog.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/aop/AnnotationSaveLoginLog.java new file mode 100644 index 0000000..a14d0b5 --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/aop/AnnotationSaveLoginLog.java @@ -0,0 +1,19 @@ +package com.zxdmy.excite.framework.aop; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *

                          + * 自定义注解:用在控制类或者控制类的方法上,用于保存登录日志 + *

                          + * + * @author 沈松 + * @since 2021/12/9 17:22 + */ +@Retention(RetentionPolicy.RUNTIME) // 何时运行和结束 +@Target({ElementType.TYPE, ElementType.METHOD}) // 注解作用位置 +public @interface AnnotationSaveLoginLog { +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/aop/AnnotationSaveReLog.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/aop/AnnotationSaveReLog.java new file mode 100644 index 0000000..c14fded --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/aop/AnnotationSaveReLog.java @@ -0,0 +1,16 @@ +package com.zxdmy.excite.framework.aop; + +import java.lang.annotation.*; + +/** + *

                          + * 自定义注解:用在控制类或者控制类的方法上,用于保存请求和响应的日志 + *

                          + * + * @author 沈松 + * @since 2021/12/9 17:22 + */ +@Retention(RetentionPolicy.RUNTIME) // 何时运行和结束 +@Target({ElementType.TYPE, ElementType.METHOD}) // 注解作用位置 +public @interface AnnotationSaveReLog { +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/aop/SaveLogAspect.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/aop/SaveLogAspect.java new file mode 100644 index 0000000..1e66f49 --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/aop/SaveLogAspect.java @@ -0,0 +1,212 @@ +package com.zxdmy.excite.framework.aop; + + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.zxdmy.excite.common.enums.SystemCode; +import com.zxdmy.excite.common.utils.HttpServletRequestUtil; +import com.zxdmy.excite.system.entity.SysLogLogin; +import com.zxdmy.excite.system.entity.SysLogRequest; +import com.zxdmy.excite.system.service.ISysLogLoginService; +import com.zxdmy.excite.system.service.ISysLogRequestService; +import lombok.AllArgsConstructor; +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.assertj.core.internal.ObjectArrays; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.Arrays; + +/** + *

                          + * AOP:保存指定请求的日志 + *

                          + * + * @author 沈松 + * @since 2021/12/9 16:45 + */ +@Aspect // AOP注解 +@Order(Ordered.HIGHEST_PRECEDENCE) +@Component +@AllArgsConstructor +public class SaveLogAspect { + + ObjectMapper objectMapper; + + ISysLogRequestService logRequestService; + + ISysLogLoginService logLoginService; + + /** + * 切入点 + */ + @Pointcut("@annotation(AnnotationSaveReLog) || @within(AnnotationSaveReLog)") + public void aspectSaveReLog() { + } + + /** + * 切入点 + */ + @Pointcut("@annotation(AnnotationSaveLoginLog) || @within(AnnotationSaveLoginLog)") + public void aspectSaveLoginLog() { + } + + /** + * AOP:保存重要请求的日志 + * + * @param pjp ProceedingJoinPoint + * @return 返回数据 + * @throws Throwable 异常 + */ + @Around("aspectSaveReLog()") + public Object saveReqLogService(ProceedingJoinPoint pjp) throws Throwable { + // 请求开始时间 + Instant start = Instant.now(); + // 请求数据实体 + SysLogRequest logRequest = new SysLogRequest(); + // 已登录?写入登录用户的ID + if (StpUtil.isLogin()) { + logRequest.setUserId(StpUtil.getLoginIdAsInt()); + } + // 写入请求的IP + logRequest.setIp(HttpServletRequestUtil.getRemoteIP()); + // 写入UA + UserAgent userAgent = HttpServletRequestUtil.getRequestUserAgent(); + logRequest.setUserAgent(userAgent.getOs().getName() + ";" + userAgent.getBrowser().getName() + " " + userAgent.getVersion()); + // 写入URI + logRequest.setReqUri(HttpServletRequestUtil.getRequestURI()); + // 写入请求方法 + logRequest.setReqMethod(HttpServletRequestUtil.getRequest().getMethod()); + // 写入请求的函数 + logRequest.setReqFunction(pjp.getSignature().toShortString()); + // 写入请求的数据 + logRequest.setReqData(objectMapper.writeValueAsString(pjp.getArgs())); + // 执行方法获取的返回值 + Object returnValue; + try { + // 执行方法 + returnValue = pjp.proceed(); + } catch (Exception e) { + // 写入返回信息(异常信息) + logRequest.setResData(e.getMessage()); + // 写入状态异常 + logRequest.setStatus(SystemCode.STATUS_N.getCode()); + // 写入时间 + logRequest.setCreateTime(LocalDateTime.now()); + // 写入执行时间间隔 + logRequest.setTimeCost((int) Duration.between(start, Instant.now()).toMillis()); + // 写入数据库 + logRequestService.save(logRequest); + // 抛出异常 + throw e; + } + // 没有异常,执行正常 + // 写入返回值 + String response = objectMapper.writeValueAsString(returnValue); + if (StrUtil.isNotEmpty(response)) { + logRequest.setResData(response); + } + // 写入请求状态 + if (JSONUtil.isJsonObj(response)) { + logRequest.setStatus(JSONUtil.parseObj(response).getBool("success", false) ? SystemCode.STATUS_Y.getCode() : SystemCode.STATUS_N.getCode()); + } + // 写入时间 + logRequest.setCreateTime(LocalDateTime.now()); + // 写入执行时间间隔 + logRequest.setTimeCost((int) Duration.between(start, Instant.now()).toMillis()); + // 写入数据库 + logRequestService.save(logRequest); + // 打印测试 +// System.out.println(logRequest); + // 返回前端 + return returnValue; + } + + /** + * AOP:保存登录日志 + * + * @param pjp ProceedingJoinPoint + * @return 返回数据 + * @throws Throwable 异常 + */ + @Around("aspectSaveLoginLog()") + public Object saveLoginLogService(ProceedingJoinPoint pjp) throws Throwable { + // 请求开始时间 + Instant start = Instant.now(); + // 请求数据实体 + SysLogLogin logLogin = new SysLogLogin(); + // 已登录?直接返回 + if (StpUtil.isLogin()) { + return pjp.proceed(); + } + // 写入请求的IP + logLogin.setIp(HttpServletRequestUtil.getRemoteIP()); + // 写入UA + UserAgent userAgent = HttpServletRequestUtil.getRequestUserAgent(); + logLogin.setUserAgent(userAgent.getOs().getName() + ";" + userAgent.getBrowser().getName() + " " + userAgent.getVersion()); + // 解析请求数据 + String request = objectMapper.writeValueAsString(pjp.getArgs()); + // System.out.println(request); + logLogin.setReqData(request); + // 写入请求用户名 + if (JSONUtil.isJsonObj(request)) { + logLogin.setUserAccount(JSONUtil.parseObj(request).getStr("username", "非法用户")); + } else if (JSONUtil.isJsonArray(request)) { + logLogin.setUserAccount(JSONUtil.parseArray(request).getStr(0, "非法用户")); + } + // 执行方法获取的返回值 + Object returnValue; + try { + returnValue = pjp.proceed(); + } catch (Exception e) { + // 写入状态异常 + logLogin.setStatus(SystemCode.STATUS_N.getCode()); + // 写入返回信息(异常信息) + logLogin.setResData(e.getMessage()); + // 写入时间 + logLogin.setCreateTime(LocalDateTime.now()); + // 写入执行时间间隔 + logLogin.setTimeCost((int) Duration.between(start, Instant.now()).toMillis()); + // 写入数据库 + logLoginService.save(logLogin); + // 抛出异常 + throw e; + } + // 没有异常,执行正常 + String response = objectMapper.writeValueAsString(returnValue); + // 如果登录成功 + if (JSONUtil.isJsonObj(response)) { + if (JSONUtil.parseObj(response).getBool("success", false)) { + logLogin.setStatus(SystemCode.STATUS_Y.getCode()); + logLogin.setUserId(StpUtil.getLoginIdAsInt()); + } + // 否则登录失败 + else { + logLogin.setStatus(SystemCode.STATUS_N.getCode()); + } + } + + // 写入返回值 + if (StrUtil.isNotEmpty(response)) { + logLogin.setResData(response); + } + + // 写入时间 + logLogin.setCreateTime(LocalDateTime.now()); + // 写入执行时间间隔 + logLogin.setTimeCost((int) Duration.between(start, Instant.now()).toMillis()); + // 写入数据库 + logLoginService.save(logLogin); + return returnValue; + } +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/Server.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/Server.java new file mode 100644 index 0000000..aad9ead --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/Server.java @@ -0,0 +1,233 @@ +package com.zxdmy.excite.framework.oshi; + +import cn.hutool.core.net.NetUtil; +import cn.hutool.core.util.NumberUtil; +import com.zxdmy.excite.common.utils.ArithUtils; +import com.zxdmy.excite.common.utils.HttpServletRequestUtil; +import com.zxdmy.excite.framework.oshi.domain.*; +import lombok.Data; +import oshi.SystemInfo; +import oshi.hardware.CentralProcessor; +import oshi.hardware.CentralProcessor.TickType; +import oshi.hardware.GlobalMemory; +import oshi.hardware.HardwareAbstractionLayer; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; +import oshi.util.Util; + +import java.io.Serializable; +import java.net.UnknownHostException; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; + +/** + * 系统服务器相关信息实体 + * + * @author 沈松 + * @since 2022/1/22 20:57 + */ +public class Server implements Serializable { + + private static final long serialVersionUID = 1L; + + private static final int OSHI_WAIT_SECOND = 1000; + + /** + * CPU相关信息 + */ + private Cpu cpu = new Cpu(); + + /** + * 內存相关信息 + */ + private Mem mem = new Mem(); + + /** + * JVM相关信息 + */ + private Jvm jvm = new Jvm(); + + /** + * 服务器相关信息 + */ + private Sys sys = new Sys(); + + /** + * 磁盘相关信息 + */ + private List sysFiles = new LinkedList(); + + public Cpu getCpu() { + return cpu; + } + + public void setCpu(Cpu cpu) { + this.cpu = cpu; + } + + public Mem getMem() { + return mem; + } + + public void setMem(Mem mem) { + this.mem = mem; + } + + public Jvm getJvm() { + return jvm; + } + + public void setJvm(Jvm jvm) { + this.jvm = jvm; + } + + public Sys getSys() { + return sys; + } + + public void setSys(Sys sys) { + this.sys = sys; + } + + public List getSysFiles() { + return sysFiles; + } + + public void setSysFiles(List sysFiles) { + this.sysFiles = sysFiles; + } + + public void copyTo() throws Exception { + SystemInfo si = new SystemInfo(); + HardwareAbstractionLayer hal = si.getHardware(); + + setCpuInfo(hal.getProcessor()); + + setMemInfo(hal.getMemory()); + + setSysInfo(); + + setJvmInfo(); + + setSysFiles(si.getOperatingSystem()); + } + + /** + * 设置CPU信息 + */ + private void setCpuInfo(CentralProcessor processor) { + // CPU信息 + long[] prevTicks = processor.getSystemCpuLoadTicks(); + Util.sleep(OSHI_WAIT_SECOND); + long[] ticks = processor.getSystemCpuLoadTicks(); + long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()]; + long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()]; + long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()]; + long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()]; + long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()]; + long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()]; + long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()]; + long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()]; + long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal; + cpu.setCpuNum(processor.getLogicalProcessorCount()); + cpu.setTotal(totalCpu); + cpu.setSys(cSys); + cpu.setUsed(user); + cpu.setWait(iowait); + cpu.setFree(idle); + } + + /** + * 设置内存信息 + */ + private void setMemInfo(GlobalMemory memory) { + long total = memory.getTotal(); + long used = memory.getTotal() - memory.getAvailable(); + mem.setTotal(convertFileSize(total)); + mem.setUsed(convertFileSize(used)); + mem.setFree(convertFileSize(memory.getAvailable())); + mem.setUsage(ArithUtils.mul(ArithUtils.div(used, total, 4), 100) + " %"); + } + + /** + * 设置服务器信息 + */ + private void setSysInfo() { + Properties props = System.getProperties(); + sys.setComputerName(HttpServletRequestUtil.getHostName()); + sys.setComputerIp(HttpServletRequestUtil.getHostIp()); + sys.setOsName(props.getProperty("os.name")); + sys.setOsArch(props.getProperty("os.arch")); + sys.setUserDir(props.getProperty("user.dir")); + } + + /** + * 设置Java虚拟机 + */ + private void setJvmInfo() { + Properties props = System.getProperties(); + // 总内存 + long total = Runtime.getRuntime().totalMemory(); + jvm.setTotal(convertFileSize(total)); + // 最大内存 + long max = Runtime.getRuntime().maxMemory(); + jvm.setMax(convertFileSize(max)); + // 空闲 + long free = Runtime.getRuntime().freeMemory(); + jvm.setFree(convertFileSize(free)); + // 已用 + jvm.setUsed(convertFileSize(total - free)); + // 使用率 + jvm.setUsage(ArithUtils.mul(ArithUtils.div(total - free, total, 4), 100) + " %"); + // 版本参数 + jvm.setVersion(props.getProperty("java.version")); + jvm.setHome(props.getProperty("java.home")); + } + + /** + * 设置磁盘信息 + */ + private void setSysFiles(OperatingSystem os) { + FileSystem fileSystem = os.getFileSystem(); + List fsArray = fileSystem.getFileStores(); + for (OSFileStore fs : fsArray) { + long free = fs.getUsableSpace(); + long total = fs.getTotalSpace(); + long used = total - free; + SysFile sysFile = new SysFile(); + sysFile.setDirName(fs.getMount()); + sysFile.setSysTypeName(fs.getType()); + sysFile.setTypeName(fs.getName()); + sysFile.setTotal(convertFileSize(total)); + sysFile.setFree(convertFileSize(free)); + sysFile.setUsed(convertFileSize(used)); + sysFile.setUsage(ArithUtils.mul(ArithUtils.div(used, total, 4), 100) + " %"); + sysFiles.add(sysFile); + } + } + + /** + * 字节转换 + * + * @param size 字节大小 + * @return 转换后值 + */ + public String convertFileSize(long size) { + long kb = 1024; + long mb = kb * 1024; + long gb = mb * 1024; + if (size >= gb) { + return String.format("%.1f GB", (float) size / gb); + } else if (size >= mb) { + float f = (float) size / mb; + return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f); + } else if (size >= kb) { + float f = (float) size / kb; + return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f); + } else { + return String.format("%d B", size); + } + } +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Cpu.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Cpu.java new file mode 100644 index 0000000..a6b3190 --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Cpu.java @@ -0,0 +1,106 @@ +package com.zxdmy.excite.framework.oshi.domain; + +import com.zxdmy.excite.common.utils.ArithUtils; + +import java.io.Serializable; + +/** + * 系统监控之:CPU信息实体 + * + * @author 沈松 + * @since 2022/1/22 20:46 + */ +public class Cpu implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 核心数 + */ + private int cpuNum; + + /** + * CPU总的使用率 + */ + private double total; + + /** + * CPU系统使用率 + */ + private double sys; + + /** + * CPU用户使用率 + */ + private double used; + + /** + * CPU当前等待率 + */ + private double wait; + + /** + * CPU当前空闲率 + */ + private double free; + + public int getCpuNum() + { + return cpuNum; + } + + public void setCpuNum(int cpuNum) + { + this.cpuNum = cpuNum; + } + + public double getTotal() + { + return ArithUtils.round(ArithUtils.mul(total, 100), 2); + } + + public void setTotal(double total) + { + this.total = total; + } + + public double getSys() + { + return ArithUtils.round(ArithUtils.mul(sys / total, 100), 2); + } + + public void setSys(double sys) + { + this.sys = sys; + } + + public double getUsed() + { + return ArithUtils.round(ArithUtils.mul(used / total, 100), 2); + } + + public void setUsed(double used) + { + this.used = used; + } + + public double getWait() + { + return ArithUtils.round(ArithUtils.mul(wait / total, 100), 2); + } + + public void setWait(double wait) + { + this.wait = wait; + } + + public double getFree() + { + return ArithUtils.round(ArithUtils.mul(free / total, 100), 2); + } + + public void setFree(double free) + { + this.free = free; + } +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Jvm.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Jvm.java new file mode 100644 index 0000000..31b1ad5 --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Jvm.java @@ -0,0 +1,130 @@ +package com.zxdmy.excite.framework.oshi.domain; + +import com.zxdmy.excite.common.utils.ArithUtils; +import com.zxdmy.excite.common.utils.DateUtils; + +import java.io.Serializable; +import java.lang.management.ManagementFactory; + +/** + * 系统监控之:Java虚拟机信息实体 + * + * @author 沈松 + * @since 2022/1/22 20:47 + */ +public class Jvm implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 当前JVM占用的内存总数 + */ + private String total; + + /** + * JVM最大可用内存总数 + */ + private String max; + + /** + * JVM已用内存数目 + */ + private String used; + + /** + * JVM空闲内存(M) + */ + private String free; + + /** + * JVM内存使用率 + */ + private String usage; + + /** + * JDK版本 + */ + private String version; + + /** + * JDK路径 + */ + private String home; + + public String getTotal() { + return total; + } + + public void setTotal(String total) { + this.total = total; + } + + public String getMax() { + return max; + } + + public void setMax(String max) { + this.max = max; + } + + public String getFree() { + return free; + } + + public void setFree(String free) { + this.free = free; + } + + public String getUsed() { + return used; + } + + public void setUsed(String used) { + this.used = used; + } + + public void setUsage(String usage) { + this.usage = usage; + } + + public String getUsage() { + return usage; + } + + /** + * 获取JDK名称 + */ + public String getName() { + return ManagementFactory.getRuntimeMXBean().getVmName(); + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getHome() { + return home; + } + + public void setHome(String home) { + this.home = home; + } + + /** + * JDK启动时间 + */ + public String getStartTime() { + return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate()); + } + + /** + * JDK运行时间 + */ + public String getRunTime() { + return DateUtils.getDatePoor(DateUtils.getNowDate(), DateUtils.getServerStartDate()); + } +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Mem.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Mem.java new file mode 100644 index 0000000..ed2ef0e --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Mem.java @@ -0,0 +1,72 @@ +package com.zxdmy.excite.framework.oshi.domain; + +import com.zxdmy.excite.common.utils.ArithUtils; + +import java.io.Serializable; + +/** + * 系统监控之:内存信息实体 + * + * @author 沈松 + * @since 2022/1/22 20:51 + */ +public class Mem implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 内存总量 + */ + private String total; + + /** + * 已用内存 + */ + private String used; + + /** + * 剩余内存 + */ + private String free; + + /** + * 使用率 + */ + private String usage; + + public String getTotal() { +// return ArithUtils.div(total, (1024 * 1024 * 1024), 2); + return total; + } + + public void setTotal(String total) { + this.total = total; + } + + public String getUsed() { +// return ArithUtils.div(used, (1024 * 1024 * 1024), 2); + return used; + } + + public void setUsed(String used) { + this.used = used; + } + + public String getFree() { +// return ArithUtils.div(free, (1024 * 1024 * 1024), 2); + return free; + } + + public void setFree(String free) { + this.free = free; + } + + public void setUsage(String usage) { + this.usage = usage; + } + + public String getUsage() { +// return ArithUtils.mul(ArithUtils.div(used, total, 4), 100); + return this.usage; + } +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Sys.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Sys.java new file mode 100644 index 0000000..fac6c79 --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/Sys.java @@ -0,0 +1,81 @@ +package com.zxdmy.excite.framework.oshi.domain; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 系统监控之:系统信息实体 + * + * @author 沈松 + * @since 2022/1/22 20:52 + */ +public class Sys implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 服务器名称 + */ + private String computerName; + + /** + * 服务器Ip + */ + private String computerIp; + + /** + * 项目路径 + */ + private String userDir; + + /** + * 操作系统 + */ + private String osName; + + /** + * 系统架构 + */ + private String osArch; + + public String getComputerName() { + return computerName; + } + + public void setComputerName(String computerName) { + this.computerName = computerName; + } + + public String getComputerIp() { + return computerIp; + } + + public void setComputerIp(String computerIp) { + this.computerIp = computerIp; + } + + public String getUserDir() { + return userDir; + } + + public void setUserDir(String userDir) { + this.userDir = userDir; + } + + public String getOsName() { + return osName; + } + + public void setOsName(String osName) { + this.osName = osName; + } + + public String getOsArch() { + return osArch; + } + + public void setOsArch(String osArch) { + this.osArch = osArch; + } +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/SysFile.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/SysFile.java new file mode 100644 index 0000000..6102114 --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/oshi/domain/SysFile.java @@ -0,0 +1,109 @@ +package com.zxdmy.excite.framework.oshi.domain; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 系统监控之:系统文件信息实体类 + * + * @author 沈松 + * @since 2022/1/22 20:53 + */ +@Data + +public class SysFile implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 盘符路径 + */ + private String dirName; + + /** + * 文件系统 + */ + private String sysTypeName; + + /** + * 盘符名称 + */ + private String typeName; + + /** + * 总大小 + */ + private String total; + + /** + * 剩余大小 + */ + private String free; + + /** + * 已经使用量 + */ + private String used; + + /** + * 资源的使用率 + */ + private String usage; + + public String getDirName() { + return dirName; + } + + public void setDirName(String dirName) { + this.dirName = dirName; + } + + public String getSysTypeName() { + return sysTypeName; + } + + public void setSysTypeName(String sysTypeName) { + this.sysTypeName = sysTypeName; + } + + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + public String getTotal() { + return total; + } + + public void setTotal(String total) { + this.total = total; + } + + public String getFree() { + return free; + } + + public void setFree(String free) { + this.free = free; + } + + public String getUsed() { + return used; + } + + public void setUsed(String used) { + this.used = used; + } + + public String getUsage() { + return usage; + } + + public void setUsage(String usage) { + this.usage = usage; + } +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/satoken/SaTokenConfig.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/satoken/SaTokenConfig.java new file mode 100644 index 0000000..cf3b32b --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/satoken/SaTokenConfig.java @@ -0,0 +1,70 @@ +package com.zxdmy.excite.framework.satoken; + +import cn.dev33.satoken.interceptor.SaAnnotationInterceptor; +import cn.dev33.satoken.interceptor.SaRouteInterceptor; +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.stp.StpUtil; + +import com.zxdmy.excite.system.entity.SysMenu; +import com.zxdmy.excite.system.service.ISysMenuService; +import lombok.AllArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.Arrays; +import java.util.List; + +/** + *

                          + * Sa-Token 配置文件 + *

                          + * + * @author 沈松 + * @since 2021-10-12 0012 19:16 + */ +@Configuration +@AllArgsConstructor +public class SaTokenConfig implements WebMvcConfigurer { + + private ISysMenuService menuService; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 方案1:注册启用【注解拦截器】 + registry.addInterceptor(new SaAnnotationInterceptor()) + // 添加:以system开头的路由都需要鉴权 + .addPathPatterns("/system/**") + // 排除:登录请求路由 + .excludePathPatterns("/system/user/login") + // 排除:登录页面路由 + .excludePathPatterns("/system/login"); + + // 方案2:注册启用【路由拦截器】 + registry.addInterceptor(new SaRouteInterceptor((request, response, handler) -> { + // 请求的完整链接 + System.out.println(request.getUrl()); + + // 可以在此处直接[批量]指定哪些路由需要拦截/排除[登录] + // SaRouter.match(Arrays.asList("/system/**", ""), Arrays.asList("/system/login", "/system/user/login"), StpUtil::checkLogin); + SaRouter.match(Arrays.asList("/system/**", "")).notMatch(Arrays.asList("/system/login", "/system/user/login")).check(StpUtil::checkLogin); + + // 可以在此处为[某个路由]指定需要的[权限] + // SaRouter.match("/system/menu/get2", () -> StpUtil.checkPermission("system:menu:get2")); + // SaRouter.match("/system/permission/get", () -> StpUtil.checkPermission("system:permission:get")); + + // 也可以从数据库中读取需要拦截的路由列表 + // getMenuList方法会访问很多次,建议使用Redis开启缓存 + List menuList = menuService.getMenuListForSaToken(); + for (SysMenu menu : menuList) { + // 如果权限标识符不为空,则添加至拦截器中 + if (null != menu.getPermission()) { + // 将访问路径Path,与对应的权限permission,添加至路由拦截器 + SaRouter.match(menu.getPath(), () -> StpUtil.checkPermission(menu.getPermission())); + } + } + + })); + + } +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/satoken/SaTokenListenerConfig.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/satoken/SaTokenListenerConfig.java new file mode 100644 index 0000000..0fc2e92 --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/satoken/SaTokenListenerConfig.java @@ -0,0 +1,83 @@ +package com.zxdmy.excite.framework.satoken; + +import cn.dev33.satoken.listener.SaTokenListener; +import cn.dev33.satoken.stp.SaLoginModel; +import org.springframework.stereotype.Component; + +/** + *

                          + * 接口SaTokenListener是Sa-Token的全局侦听器,通过实现此接口,你可以在用户登陆、退出、被踢下线等关键性操作时进行一些AOP操作,比如保存登录/退出日志等信息。 + * 详情:https://sa-token.dev33.cn/doc/index.html#/up/global-listener + *

                          + * + * @author 沈松 + * @since 2021-10-14 0014 17:22 + */ +@Component +public class SaTokenListenerConfig implements SaTokenListener { + + /** + * 每次登录时触发 + */ + @Override + public void doLogin(String loginType, Object loginId, SaLoginModel loginModel) { + System.out.println(loginType + loginId + loginModel); + } + + /** + * 每次注销时触发 + */ + @Override + public void doLogout(String loginType, Object loginId, String tokenValue) { + // ... + } + + /** + * 每次被踢下线时触发 + */ + @Override + public void doKickout(String loginType, Object loginId, String tokenValue) { + // ... + } + + /** + * 每次被顶下线时触发 + */ + @Override + public void doReplaced(String loginType, Object loginId, String tokenValue) { + // ... + } + + /** + * 每次被封禁时触发 + */ + @Override + public void doDisable(String loginType, Object loginId, long disableTime) { + // ... + } + + /** + * 每次被解封时触发 + */ + @Override + public void doUntieDisable(String loginType, Object loginId) { + // ... + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCreateSession(String id) { + // ... + } + + /** + * 每次注销Session时触发 + */ + @Override + public void doLogoutSession(String id) { + // ... + } + +} diff --git a/ss-framework/src/main/java/com/zxdmy/excite/framework/satoken/SaTokenStpInterfaceImpl.java b/ss-framework/src/main/java/com/zxdmy/excite/framework/satoken/SaTokenStpInterfaceImpl.java new file mode 100644 index 0000000..12ee534 --- /dev/null +++ b/ss-framework/src/main/java/com/zxdmy/excite/framework/satoken/SaTokenStpInterfaceImpl.java @@ -0,0 +1,49 @@ +package com.zxdmy.excite.framework.satoken; + +import cn.dev33.satoken.stp.StpInterface; +import com.zxdmy.excite.system.entity.SysMenu; +import com.zxdmy.excite.system.service.ISysMenuService; +import com.zxdmy.excite.system.service.ISysRoleService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 权限认证接口 + *

                          + * + * @author 沈松 + * @since 2021-10-12 0012 21:02 + */ +@Component +@AllArgsConstructor +public class SaTokenStpInterfaceImpl implements StpInterface { + + private ISysMenuService menuService; + + private ISysRoleService roleService; + + @Override + public List getPermissionList(Object userId, String userType) { + List menuList = menuService.getMenuListByUserIdForSaToken(Integer.valueOf(userId.toString())); + if (null == menuList) { + return null; + } + // 筛选,取出非空权限(href != null) + List permissions = new ArrayList<>(); + for (SysMenu menu : menuList) { + if (null != menu.getPermission() && !"".equals(menu.getPermission())) { + permissions.add(menu.getPermission()); + } + } + return permissions; + } + + @Override + public List getRoleList(Object userId, String userType) { + return null; + } +} diff --git a/ss-system/README.md b/ss-system/README.md new file mode 100644 index 0000000..f384673 --- /dev/null +++ b/ss-system/README.md @@ -0,0 +1,3 @@ +# Ss-System 模块 + +主要实现系统管理模块的相关功能(实体类、服务类、Mapper类) diff --git a/ss-system/pom.xml b/ss-system/pom.xml new file mode 100644 index 0000000..5fd072e --- /dev/null +++ b/ss-system/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + com.zxdmy.excite + shensong + 2.0.0 + + + ss-system + 2.0.0 + ss-system + + 【系统】模块,主要实现与system前缀表的数据库交互Dao和服务类Service。 + + + + + + + com.zxdmy.excite + ss-common + 2.0.0 + + + + + diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysLogLogin.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysLogLogin.java new file mode 100644 index 0000000..545d06d --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysLogLogin.java @@ -0,0 +1,95 @@ +package com.zxdmy.excite.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * + *

                          + * + * @author 沈松 + * @since 2021-12-28 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class SysLogLogin implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 登录用户ID + */ + private Integer userId; + + /** + * 登录用户账号 + */ + private String userAccount; + + /** + * 登录IP + */ + private String ip; + + /** + * 浏览器Agent + */ + private String userAgent; + + /** + * 请求数据 + */ + private String reqData; + + /** + * 返回数据 + */ + private String resData; + + /** + * 耗时 + */ + private Integer timeCost; + + /** + * 请求状态:0-失败 | 1-成功 + */ + private Integer status; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonSerialize(using = LocalDateTimeSerializer.class) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 删除时间 + */ + private LocalDateTime deleteTime; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysLogRequest.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysLogRequest.java new file mode 100644 index 0000000..3802248 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysLogRequest.java @@ -0,0 +1,107 @@ +package com.zxdmy.excite.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.time.LocalDateTime; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * + *

                          + * + * @author 沈松 + * @since 2021-12-09 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class SysLogRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 请求用户ID + */ + private Integer userId; + + /** + * 请求IP + */ + private String ip; + + /** + * 浏览器Agent + */ + private String userAgent; + + /** + * 请求的URI + */ + private String reqUri; + + /** + * 请求方法:GET | POST | DELETE + */ + private String reqMethod; + /** + * 请求的函数 + */ + private String reqFunction; + + /** + * 请求的数据 + */ + private String reqData; + + /** + * 返回的数据 + */ + private String resData; + + /** + * 耗时,单位:ms + */ + private Integer timeCost; + + /** + * 耗时,单位:ms + */ + private Integer status; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonSerialize(using = LocalDateTimeSerializer.class) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + private LocalDateTime updateTime; + + /** + * 删除时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + private LocalDateTime deleteTime; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysMenu.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysMenu.java new file mode 100644 index 0000000..5c010e5 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysMenu.java @@ -0,0 +1,145 @@ +package com.zxdmy.excite.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +/** + *

                          + * 系统菜单/权限表 + *

                          + * 不返回为null的字段 + * + * @author 沈松 + * @since 2021-09-12 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SysMenu implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 菜单/权限ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 菜单/权限名称 + */ + @NotBlank(message = "菜单名称不能为空") + @JsonProperty("title") + private String name; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 菜单/权限路由:对于后台控制类定义,示例:system/user/get/{id} + */ + @JsonProperty("href") + private String path; + + /** + * 权限标识符:对于后台控制类定义。示例:system:user:list + */ + @NotBlank(message = "权限标识不能为空") + private String permission; + + /** + * 组件路径:对于前端框架定义。示例:system/user/index + */ + private String component; + + /** + * 上级菜单ID + */ + private Integer parentId; + + /** + * 菜单类型:N - 顶部菜单 | C - 目录 | M - 菜单 | B - 按钮 + */ + @NotBlank(message = "菜单类型不能为空") + private String type; + + /** + * 排序:数值越大越靠前 + */ + @NotNull(message = "菜单显示顺序不能为空") + private Integer sort; + + /** + * 可编辑:0-禁止编辑 | 1-可编辑 + */ + private Integer editable; + + /** + * 可删除:0-禁止删除 | 1-可删除 + */ + private Integer removable; + + /** + * 菜单状态:0-封禁 | 1-正常 | 2-正常且禁止封禁 + */ + private Integer status; + + /** + * 是否删除:0-未删除 | 1-已删除 + */ + @JsonIgnore + private Integer isDelete; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonSerialize(using = LocalDateTimeSerializer.class) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonSerialize(using = LocalDateTimeSerializer.class) + private LocalDateTime updateTime; + + /** + * 删除时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonSerialize(using = LocalDateTimeSerializer.class) + private LocalDateTime deleteTime; + + /** + * 子菜单列表 + */ + @TableField(exist = false) + private List child; + + /** + * 复选框使用的字段,默认为"0",选中为"1", + */ + @TableField(exist = false) + private String checkArr = "0"; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysRole.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysRole.java new file mode 100644 index 0000000..5492257 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysRole.java @@ -0,0 +1,105 @@ +package com.zxdmy.excite.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 系统角色表 + *

                          + * + * @author 沈松 + * @since 2021-09-23 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class SysRole implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 角色名称 + */ + @NotBlank(message = "角色名称不能为空") + private String name; + + /** + * 角色权限标识符,如:admin、guest + */ + @NotBlank(message = "权限标识符不能为空") + private String permission; + + /** + * 备注 + */ + private String remark; + + /** + * 排序:数值越大越靠前 + */ + private Integer sort; + + /** + * 角色状态:0-封禁 | 1-正常 | 2-正常且禁止封禁 + */ + private Integer status; + + /** + * 是否删除:0-未删除 | 1-已删除 + */ + @TableLogic + @JsonIgnore + private Integer isDelete; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + private LocalDateTime updateTime; + + /** + * 删除时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + private LocalDateTime deleteTime; + + + /** + * 复选框使用的字段,默认为"0",选中为"1", + */ + @TableField(exist = false) + private String checkArr = "0"; + + @TableField(exist = false) + private String parentId = "-1"; + + /** + * 前端Layui表格中,多选框使用 + */ + @TableField(exist = false) + @JsonProperty("LAY_CHECKED") + private Boolean LAY_CHECKED = false; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysRoleMenu.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysRoleMenu.java new file mode 100644 index 0000000..6f2fc06 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysRoleMenu.java @@ -0,0 +1,41 @@ +package com.zxdmy.excite.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + *

                          + * 系统角色和菜单/权限关联表 + *

                          + * + * @author 沈松 + * @since 2021-09-16 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class SysRoleMenu implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 角色菜单关联ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 角色ID + */ + private Integer roleId; + + /** + * 菜单/权限ID + */ + private Integer menuId; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysUser.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysUser.java new file mode 100644 index 0000000..3c44cd9 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysUser.java @@ -0,0 +1,128 @@ +package com.zxdmy.excite.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 系统用户表 + *

                          + * + * @author 沈松 + * @since 2021-09-01 + */ +@Schema(name = "SysUser", description = "系统用户实体") +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SysUser implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 用户主键 + */ + @TableId(value = "id", type = IdType.AUTO) + @Schema(name = "id",description = "用户主键") + private Integer id; + + /** + * 用户昵称 + */ + @Schema(name = "username",description = "用户昵称") + private String username; + + /** + * 用户头像 + */ + @Schema(name = "avatar",description = "用户头像") + private String avatar; + + /** + * 用户性别(0-未知 | 1-男 | 2-女) + */ + private Integer sex; + + /** + * 用户邮箱 + */ + private String loginName; + + /** + * 用户手机号 + */ + private String phone; + + /** + * 用户密码 + */ + @JsonIgnore + private String password; + + /** + * 用户状态 + */ +// @JsonIgnore + private Integer status; + + /** + * 用户备注信息 + */ + private String remark; + + /** + * 登录IP + */ + private String loginIp; + + /** + * 登录时间 + */ + private LocalDateTime loginDate; + + /** + * 是否删除(0-未删除 | 1-已删除) + */ + @TableLogic + @JsonIgnore + private Integer isDelete; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonSerialize(using = LocalDateTimeSerializer.class) + private LocalDateTime createTime; + + /** + * 更新时间 + */ +// @JsonIgnore + @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8") + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonSerialize(using = LocalDateTimeSerializer.class) + private LocalDateTime updateTime; + + /** + * 删除时间 + */ + @JsonIgnore + private LocalDateTime deleteTime; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysUserRole.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysUserRole.java new file mode 100644 index 0000000..e24c5de --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/SysUserRole.java @@ -0,0 +1,41 @@ +package com.zxdmy.excite.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + *

                          + * 系统用户和角色关联表 + *

                          + * + * @author 沈松 + * @since 2021-09-23 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class SysUserRole implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 用户角色关联ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 用户ID + */ + private Integer userId; + + /** + * 角色ID + */ + private Integer roleId; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/account/CloudCompany.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/account/CloudCompany.java new file mode 100644 index 0000000..e958f06 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/account/CloudCompany.java @@ -0,0 +1,70 @@ +package com.zxdmy.excite.system.entity.cloud.account; + +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 企业表 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudCompany implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 企业名称 + */ + private String companyName; + + /** + * 排序 + */ + private Integer companySort; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 创建者ID + */ + private Integer creatorId; + + /** + * 创建者姓名 + */ + private String creatorName; + /** + * 删除时间 + */ + private LocalDateTime deleteTime; + + /** + * 删除者ID + */ + private Integer deleteId; + + /** + * 删除者姓名 + */ + private String deleteName; + + @TableField(exist=false) + private String title; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/account/CloudDepartment.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/account/CloudDepartment.java new file mode 100644 index 0000000..61964b3 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/account/CloudDepartment.java @@ -0,0 +1,77 @@ +package com.zxdmy.excite.system.entity.cloud.account; + +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 部门表 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudDepartment implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 部门名称 + */ + private String departmentName; + + /** + * 排序 + */ + private Integer departmentSort; + + /** + * 上级部门ID + */ + private Long departmentParentId; + + private Long companyId; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 创建者ID + */ + private Integer creatorId; + + /** + * 创建者姓名 + */ + private String creatorName; + + /** + * 删除时间 + */ + private LocalDateTime deleteTime; + + /** + * 删除者ID + */ + private Integer deleteId; + + /** + * 删除者姓名 + */ + private String deleteName; + @TableField(exist=false) + private String title; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/account/CloudDepartmentUser.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/account/CloudDepartmentUser.java new file mode 100644 index 0000000..98408d5 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/account/CloudDepartmentUser.java @@ -0,0 +1,37 @@ +package com.zxdmy.excite.system.entity.cloud.account; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 部门用户ID + *

                          + * + * @author ss + * @since 2026-01-27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudDepartmentUser implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 部门ID + */ + private Long departmentId; + + /** + * 用户ID + */ + private Integer userId; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/collection/CloudUserCollection.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/collection/CloudUserCollection.java new file mode 100644 index 0000000..fafcd82 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/collection/CloudUserCollection.java @@ -0,0 +1,43 @@ +package com.zxdmy.excite.system.entity.cloud.collection; + +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 收藏表 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudUserCollection implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 文件ID + */ + private Long fileId; + + /** + * 收藏者ID + */ + private Integer userId; + + /** + * 收藏时间 + */ + private LocalDateTime createTime; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/lately/CloudUserLately.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/lately/CloudUserLately.java new file mode 100644 index 0000000..bed317d --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/lately/CloudUserLately.java @@ -0,0 +1,48 @@ +package com.zxdmy.excite.system.entity.cloud.lately; + +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 最近文件表 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudUserLately implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 文件ID + */ + private Long fileId; + + /** + * 用户ID + */ + private Integer userId; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 最近打开时间 + */ + private LocalDateTime latelyTime; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/role/CloudRole.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/role/CloudRole.java new file mode 100644 index 0000000..c0b6fe3 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/role/CloudRole.java @@ -0,0 +1,93 @@ +package com.zxdmy.excite.system.entity.cloud.role; + +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 云盘权限表 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudRole implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 权限名称 + */ + private String roleName; + + /** + * 上传权限 + */ + private Integer roleUpload; + + /** + * 下载权限 + */ + private Integer roleDown; + private Integer roleDelete; + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 创建者ID + */ + private Integer creatorId; + + /** + * 创建者姓名 + */ + private String creatorName; + + /** + * 删除时间 + */ + private LocalDateTime deleteTime; + + /** + * 删除者ID + */ + private Integer deleteId; + + /** + * 删除者姓名 + */ + private String deleteName; + + /** + * 复选框使用的字段,默认为"0",选中为"1", + */ + @TableField(exist = false) + private String checkArr = "0"; + + @TableField(exist = false) + private String parentId = "-1"; + + /** + * 前端Layui表格中,多选框使用 + */ + @TableField(exist = false) + @JsonProperty("LAY_CHECKED") + private Boolean LAY_CHECKED = false; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/role/CloudRoleFile.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/role/CloudRoleFile.java new file mode 100644 index 0000000..4c0dbd2 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/role/CloudRoleFile.java @@ -0,0 +1,38 @@ +package com.zxdmy.excite.system.entity.cloud.role; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 云盘权限文件表 + *

                          + * + * @author 沈松 + * @since 2026-02-01 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudRoleFile implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 权限ID + */ + private Long roleId; + + /** + * 文件目录ID + */ + private Long fileId; + + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/role/CloudRoleUser.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/role/CloudRoleUser.java new file mode 100644 index 0000000..2b630e4 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/role/CloudRoleUser.java @@ -0,0 +1,37 @@ +package com.zxdmy.excite.system.entity.cloud.role; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 云盘权限用户表 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudRoleUser implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 权限ID + */ + private Long roleId; + + /** + * 用户ID + */ + private Integer userId; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/space/CloudFile.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/space/CloudFile.java new file mode 100644 index 0000000..d5ad7cb --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/space/CloudFile.java @@ -0,0 +1,132 @@ +package com.zxdmy.excite.system.entity.cloud.space; + +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 文件表 + *

                          + * + * @author ss + * @since 2026-01-28 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudFile implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件大小 + */ + private String fileSize; + + /** + * 文件格式 + */ + private String fileFormat; + + /** + * 文件OSS地址 + */ + private String fileOss; + + /** + * 文件封面地址 + */ + private String fileImage; + + /** + * 文件排序 + */ + private Integer fileSort; + + /** + * 0是文件夹 1是文件 + */ + private Integer fileFolder; + + /** + * 父级文件ID + */ + private Long fileParentId; + + /** + * 顶级文件ID + */ + private Long fileTopId; + + /** + * 云盘结构目录 + */ + private String fileFolderPath; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 创建者ID + */ + private Integer creatorId; + + /** + * 创建者姓名 + */ + private String creatorName; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 更新者ID + */ + private Integer updaterId; + + /** + * 更新者姓名 + */ + private String updaterName; + + /** + * 删除时间 + */ + @TableField(updateStrategy = FieldStrategy.IGNORED) + private LocalDateTime deleteTime; + + /** + * 删除者ID + */ + @TableField(updateStrategy = FieldStrategy.IGNORED) + private Integer deleteId; + + /** + * 删除者姓名 + */ + @TableField(updateStrategy = FieldStrategy.IGNORED) + private String deleteName; + + private Integer fileTop; + + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/space/CloudFileRole.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/space/CloudFileRole.java new file mode 100644 index 0000000..f3090ae --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/space/CloudFileRole.java @@ -0,0 +1,37 @@ +package com.zxdmy.excite.system.entity.cloud.space; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 文件用户权限表 + *

                          + * + * @author 沈松 + * @since 2026-01-30 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudFileRole implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 文件ID + */ + private Long fileId; + + /** + * 用户ID + */ + private Integer userId; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/trace/CloudFileTrace.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/trace/CloudFileTrace.java new file mode 100644 index 0000000..e29731d --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/cloud/trace/CloudFileTrace.java @@ -0,0 +1,53 @@ +package com.zxdmy.excite.system.entity.cloud.trace; + +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

                          + * 文件痕迹 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudFileTrace implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 操作名称 + */ + private String traceName; + + /** + * 操作者ID + */ + private Integer traceCreatorId; + + /** + * 操作者姓名 + */ + private String traceCreatorName; + + /** + * 操作时间 + */ + private LocalDateTime createTime; + + /** + * 操作文件ID + */ + private Long fileId; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/DepartmentTreeDTO.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/DepartmentTreeDTO.java new file mode 100644 index 0000000..d3aa478 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/DepartmentTreeDTO.java @@ -0,0 +1,22 @@ +package com.zxdmy.excite.system.entity.dto; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.util.List; + +@Data +public class DepartmentTreeDTO { + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + private String title; + private String departmentName; + private Integer departmentSort; + @JsonSerialize(using = ToStringSerializer.class) + private Long departmentParentId; + @JsonSerialize(using = ToStringSerializer.class) + private Long companyId; + private List children; + private Boolean spread = true; // Layui树节点是否展开 +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/DepartmentUserTreeNode.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/DepartmentUserTreeNode.java new file mode 100644 index 0000000..fe14cfd --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/DepartmentUserTreeNode.java @@ -0,0 +1,52 @@ +package com.zxdmy.excite.system.entity.dto; + +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartment; +import lombok.Data; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Data +public class DepartmentUserTreeNode { + private Long id; + private String title; + private String type; // 'department' 或 'user' + private Integer sort; + private Long parentId; + private Long departmentId; // 用户所属部门ID + private Boolean isLeaf; // 是否为叶子节点(用户节点为true) + private Map attributes = new HashMap<>(); + private List children = new ArrayList<>(); + + // 部门构造器 + public DepartmentUserTreeNode(CloudDepartment dept) { + this.id = dept.getId(); + this.title = dept.getDepartmentName(); + this.type = "department"; + this.sort = dept.getDepartmentSort(); + this.parentId = dept.getDepartmentParentId(); + this.isLeaf = false; + this.attributes.put("id", dept.getId()); + this.attributes.put("departmentName", dept.getDepartmentName()); + this.attributes.put("sort", dept.getDepartmentSort()); + this.attributes.put("parentId", dept.getDepartmentParentId()); + this.attributes.put("companyId", dept.getCompanyId()); + } + + // 用户构造器 + public DepartmentUserTreeNode(SysUser user, Long departmentId) { + this.id = user.getId().longValue(); + this.title = user.getUsername(); + this.type = "user"; + this.sort = 0; + this.parentId = departmentId; // 父节点是部门ID + this.departmentId = departmentId; + this.isLeaf = true; + this.attributes.put("id", user.getId()); + this.attributes.put("username", user.getUsername()); + this.attributes.put("departmentId", departmentId); + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/FileTreeDTO.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/FileTreeDTO.java new file mode 100644 index 0000000..16aff84 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/FileTreeDTO.java @@ -0,0 +1,21 @@ +package com.zxdmy.excite.system.entity.dto; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.util.List; + +@Data +public class FileTreeDTO { + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + private String title; + @JsonSerialize(using = ToStringSerializer.class) + private Long fileParentId; + private Integer fileSort; + private List children; + private Boolean spread = true; // Layui树节点是否展开 + + private String checked; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/RoleTreeDTO.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/RoleTreeDTO.java new file mode 100644 index 0000000..ef8acfa --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/dto/RoleTreeDTO.java @@ -0,0 +1,17 @@ +package com.zxdmy.excite.system.entity.dto; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.util.List; + +@Data +public class RoleTreeDTO { + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + private String name; + private String parentId = "-1"; + private String checkArr = "0"; + private String checked; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/account/ReqCompany.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/account/ReqCompany.java new file mode 100644 index 0000000..53efdde --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/account/ReqCompany.java @@ -0,0 +1,26 @@ +package com.zxdmy.excite.system.entity.req.account; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 企业表 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class ReqCompany implements Serializable { + private String id; + @NotNull(message = "企业名称为空") + private String companyName; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/account/ReqDepartment.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/account/ReqDepartment.java new file mode 100644 index 0000000..c99eac8 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/account/ReqDepartment.java @@ -0,0 +1,26 @@ +package com.zxdmy.excite.system.entity.req.account; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + *

                          + * 企业表 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class ReqDepartment implements Serializable { + private String id; + @NotNull(message = "部门名称为空") + private String departmentName; + private String companyId; + private String departmentParentId; + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/collection/ReqCloudUserCollection.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/collection/ReqCloudUserCollection.java new file mode 100644 index 0000000..3b3c8cf --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/collection/ReqCloudUserCollection.java @@ -0,0 +1,41 @@ +package com.zxdmy.excite.system.entity.req.collection; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 收藏表 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class ReqCloudUserCollection implements Serializable { + + private String id; + + /** + * 文件ID + */ + private String fileId; + + /** + * 收藏者ID + */ + private Integer userId; + + /** + * 收藏时间 + */ + private LocalDateTime createTime; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/lately/ReqCloudUserLately.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/lately/ReqCloudUserLately.java new file mode 100644 index 0000000..f922f50 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/lately/ReqCloudUserLately.java @@ -0,0 +1,36 @@ +package com.zxdmy.excite.system.entity.req.lately; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 最近文件表 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class ReqCloudUserLately implements Serializable { + + private String id; + + /** + * 文件ID + */ + private String fileId; + + /** + * 用户ID + */ + private Integer userId; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/role/ReqRole.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/role/ReqRole.java new file mode 100644 index 0000000..8353746 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/role/ReqRole.java @@ -0,0 +1,27 @@ +package com.zxdmy.excite.system.entity.req.role; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + *

                          + * 企业表 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class ReqRole implements Serializable { + private String id; + @NotNull(message = "权限名称为空") + private String roleName; + private Integer roleUpload; + private Integer roleDown; + private Integer roleDelete; + private String[] ids; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/space/ReqCloudFile.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/space/ReqCloudFile.java new file mode 100644 index 0000000..27c6628 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/space/ReqCloudFile.java @@ -0,0 +1,90 @@ +package com.zxdmy.excite.system.entity.req.space; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

                          + * 文件表 + *

                          + * + * @author ss + * @since 2026-01-28 + */ +@Data +public class ReqCloudFile implements Serializable { + + + private String id; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 父级文件ID + */ + private String fileParentId; + + /** + * 顶级文件ID + */ + private String fileTopId; + + /** + * 云盘结构目录 + */ + private String fileFolderPath; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 创建者ID + */ + private Integer creatorId; + + /** + * 创建者姓名 + */ + private String creatorName; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 更新者ID + */ + private Integer updaterId; + + /** + * 更新者姓名 + */ + private String updaterName; + + private String fileOss; + + private Integer fileFolder; + + private String fileSize; + + private Integer[] ids; + + private Integer userId; + + private Integer fileTop; + + + private List fileIds; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/space/ReqCloudFileRole.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/space/ReqCloudFileRole.java new file mode 100644 index 0000000..ba3c6d4 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/space/ReqCloudFileRole.java @@ -0,0 +1,34 @@ +package com.zxdmy.excite.system.entity.req.space; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.List; + +/** + *

                          + * 文件用户权限表 + *

                          + * + * @author 沈松 + * @since 2026-01-30 + */ +@Data +public class ReqCloudFileRole implements Serializable { + + private String id; + + /** + * 文件ID + */ + private String fileId; + + /** + * 用户ID + */ + private Integer userId; + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/trace/ReqCloudFileTrace.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/trace/ReqCloudFileTrace.java new file mode 100644 index 0000000..a4a003d --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/req/trace/ReqCloudFileTrace.java @@ -0,0 +1,51 @@ +package com.zxdmy.excite.system.entity.req.trace; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 文件痕迹 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class ReqCloudFileTrace implements Serializable { + + private String id; + + /** + * 操作名称 + */ + private String traceName; + + /** + * 操作者ID + */ + private Integer traceCreatorId; + + /** + * 操作者姓名 + */ + private String traceCreatorName; + + /** + * 操作时间 + */ + private LocalDateTime createTime; + + /** + * 操作文件ID + */ + private String fileId; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/account/CompanyVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/account/CompanyVo.java new file mode 100644 index 0000000..8a4a6f8 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/account/CompanyVo.java @@ -0,0 +1,83 @@ +package com.zxdmy.excite.system.entity.vo.account; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 企业表 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CompanyVo implements Serializable { + + + private String id; + + /** + * 企业名称 + */ + private String companyName; + + /** + * 排序 + */ + private Integer companySort; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + /** + * 创建者ID + */ + private String creatorId; + + /** + * 创建者姓名 + */ + private String creatorName; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + /** + * 更新者ID + */ + private String updaterId; + + /** + * 更新者姓名 + */ + private String updaterName; + + /** + * 删除时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime deleteTime; + + /** + * 删除者ID + */ + private String deleteId; + + /** + * 删除者姓名 + */ + private String deleteName; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/account/DepartmentVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/account/DepartmentVo.java new file mode 100644 index 0000000..9b61713 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/account/DepartmentVo.java @@ -0,0 +1,73 @@ +package com.zxdmy.excite.system.entity.vo.account; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 企业表 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class DepartmentVo implements Serializable { + + + private String id; + + /** + * 部门名称 + */ + private String departmentName; + + /** + * 排序 + */ + private Integer departmentSort; + + /** + * 上级部门ID + */ + private String departmentParentId; + private String companyId; + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + /** + * 创建者ID + */ + private Integer creatorId; + + /** + * 创建者姓名 + */ + private String creatorName; + + /** + * 删除时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime deleteTime; + + /** + * 删除者ID + */ + private Integer deleteId; + + /** + * 删除者姓名 + */ + private String deleteName; + + private String companyName; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/collection/CloudUserCollectionVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/collection/CloudUserCollectionVo.java new file mode 100644 index 0000000..f116af5 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/collection/CloudUserCollectionVo.java @@ -0,0 +1,45 @@ +package com.zxdmy.excite.system.entity.vo.collection; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 收藏表 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudUserCollectionVo implements Serializable { + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** + * 文件ID + */ + private Long fileId; + + /** + * 收藏者ID + */ + private Integer userId; + + /** + * 收藏时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/lately/CloudUserLatelyVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/lately/CloudUserLatelyVo.java new file mode 100644 index 0000000..149db7b --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/lately/CloudUserLatelyVo.java @@ -0,0 +1,52 @@ +package com.zxdmy.excite.system.entity.vo.lately; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 最近文件表 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudUserLatelyVo implements Serializable { + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** + * 文件ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long fileId; + + /** + * 用户ID + */ + private Integer userId; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + /** + * 最近打开时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime latelyTime; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/role/RoleVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/role/RoleVo.java new file mode 100644 index 0000000..c572a9d --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/role/RoleVo.java @@ -0,0 +1,78 @@ +package com.zxdmy.excite.system.entity.vo.role; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 云盘权限表 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class RoleVo implements Serializable { + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** + * 权限名称 + */ + private String roleName; + + /** + * 上传权限 + */ + private Integer roleUpload; + + /** + * 下载权限 + */ + private Integer roleDown; + + private Integer roleDelete; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + /** + * 创建者ID + */ + private Integer creatorId; + + /** + * 创建者姓名 + */ + private String creatorName; + + /** + * 删除时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime deleteTime; + + /** + * 删除者ID + */ + private Integer deleteId; + + /** + * 删除者姓名 + */ + private String deleteName; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudFileRoleVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudFileRoleVo.java new file mode 100644 index 0000000..d09aac1 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudFileRoleVo.java @@ -0,0 +1,42 @@ +package com.zxdmy.excite.system.entity.vo.space; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + *

                          + * 文件用户权限表 + *

                          + * + * @author 沈松 + * @since 2026-01-30 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudFileRoleVo implements Serializable { + + + private Long id; + + /** + * 文件ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long fileId; + + /** + * 用户ID + */ + private Integer userId; + + + private String userName; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudFileVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudFileVo.java new file mode 100644 index 0000000..2987306 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudFileVo.java @@ -0,0 +1,140 @@ +package com.zxdmy.excite.system.entity.vo.space; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 文件表 + *

                          + * + * @author ss + * @since 2026-01-28 + */ +@Data +public class CloudFileVo implements Serializable { + + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件大小 + */ + private String fileSize; + + /** + * 文件格式 + */ + private String fileFormat; + + /** + * 文件OSS地址 + */ + private String fileOss; + + /** + * 文件封面地址 + */ + private String fileImage; + + /** + * 文件排序 + */ + private Integer fileSort; + + /** + * 0是文件夹 1是文件 + */ + private Integer fileFolder; + + /** + * 父级文件ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long fileParentId; + + /** + * 顶级文件ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long fileTopId; + + /** + * 云盘结构目录 + */ + private String fileFolderPath; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + /** + * 创建者ID + */ + private Integer creatorId; + + /** + * 创建者姓名 + */ + private String creatorName; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + /** + * 更新者ID + */ + private Integer updaterId; + + /** + * 更新者姓名 + */ + private String updaterName; + + /** + * 删除时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime deleteTime; + + /** + * 删除者ID + */ + private Integer deleteId; + + /** + * 删除者姓名 + */ + private String deleteName; + + + + private Integer roleUpload; + private Integer roleDown; + private Integer roleDelete; + + private Integer fileTop; + + private String title; + + private String checked; + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudFilleUserVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudFilleUserVo.java new file mode 100644 index 0000000..004815e --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudFilleUserVo.java @@ -0,0 +1,26 @@ +package com.zxdmy.excite.system.entity.vo.space; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

                          + * 文件表 + *

                          + * + * @author ss + * @since 2026-01-28 + */ +@Data +public class CloudFilleUserVo implements Serializable { + + private List ids; + private String userId; + private String name; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudRoleFileVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudRoleFileVo.java new file mode 100644 index 0000000..1673073 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudRoleFileVo.java @@ -0,0 +1,34 @@ +package com.zxdmy.excite.system.entity.vo.space; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + *

                          + * 文件用户权限表 + *

                          + * + * @author 沈松 + * @since 2026-01-30 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudRoleFileVo implements Serializable { + + + private Long id; + + @JsonSerialize(using = ToStringSerializer.class) + private Long fileId; + + private Long roleId; + + + private String fileName; + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudRoleFolderVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudRoleFolderVo.java new file mode 100644 index 0000000..2ad9b94 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/space/CloudRoleFolderVo.java @@ -0,0 +1,22 @@ +package com.zxdmy.excite.system.entity.vo.space; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + *

                          + * 文件表 + *

                          + * + * @author ss + * @since 2026-01-28 + */ +@Data +public class CloudRoleFolderVo implements Serializable { + + private List ids; + private String roleId; + private String name; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/trace/CloudFileTraceVo.java b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/trace/CloudFileTraceVo.java new file mode 100644 index 0000000..640afee --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/entity/vo/trace/CloudFileTraceVo.java @@ -0,0 +1,57 @@ +package com.zxdmy.excite.system.entity.vo.trace; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

                          + * 文件痕迹 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class CloudFileTraceVo implements Serializable { + + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + /** + * 操作名称 + */ + private String traceName; + + /** + * 操作者ID + */ + private Integer traceCreatorId; + + /** + * 操作者姓名 + */ + private String traceCreatorName; + + /** + * 操作时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + /** + * 操作文件ID + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long fileId; + + private String fileOss; +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysLogLoginMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysLogLoginMapper.java new file mode 100644 index 0000000..a1c12d8 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysLogLoginMapper.java @@ -0,0 +1,16 @@ +package com.zxdmy.excite.system.mapper; + +import com.zxdmy.excite.system.entity.SysLogLogin; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

                          + * Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2021-12-28 + */ +public interface SysLogLoginMapper extends BaseMapper { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysLogRequestMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysLogRequestMapper.java new file mode 100644 index 0000000..f11b925 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysLogRequestMapper.java @@ -0,0 +1,16 @@ +package com.zxdmy.excite.system.mapper; + +import com.zxdmy.excite.system.entity.SysLogRequest; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

                          + * Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2021-12-09 + */ +public interface SysLogRequestMapper extends BaseMapper { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysMenuMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysMenuMapper.java new file mode 100644 index 0000000..41c88df --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysMenuMapper.java @@ -0,0 +1,37 @@ +package com.zxdmy.excite.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sun.org.apache.xpath.internal.operations.Bool; +import com.zxdmy.excite.system.entity.SysMenu; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + *

                          + * 系统菜单/角色表 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2021-09-12 + */ +@Repository +public interface SysMenuMapper extends BaseMapper { + + /** + * 根据角色ID查询菜单/权限(不含禁用) + * + * @param roleId 角色ID + * @return 菜单/权限列表 + */ + List selectMenusByRoleId(Integer roleId); + + /** + * 根据用户的ID查询菜单/权限(不含禁用) + * + * @param userId 用户的ID + * @param isOnlyMenu 是否只包含菜单:1:只返回菜单 | 0:返回包含菜单+按钮 + * @return 菜单/权限列表 + */ + List selectMenusByUserId(Integer userId, int isOnlyMenu); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysRoleMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysRoleMapper.java new file mode 100644 index 0000000..4697014 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysRoleMapper.java @@ -0,0 +1,18 @@ +package com.zxdmy.excite.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.SysRole; +import org.springframework.stereotype.Repository; + +/** + *

                          + * 系统角色表 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2021-09-23 + */ +@Repository +public interface SysRoleMapper extends BaseMapper { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysRoleMenuMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 0000000..ec343a0 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,18 @@ +package com.zxdmy.excite.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.SysRoleMenu; +import org.springframework.stereotype.Repository; + +/** + *

                          + * 系统角色和菜单/权限关联表 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2021-09-16 + */ +@Repository +public interface SysRoleMenuMapper extends BaseMapper { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysUserMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysUserMapper.java new file mode 100644 index 0000000..cde1f74 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysUserMapper.java @@ -0,0 +1,48 @@ +package com.zxdmy.excite.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.req.account.ReqDepartment; +import com.zxdmy.excite.system.entity.vo.account.DepartmentVo; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 系统用户表 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2021-09-01 + */ +@Repository +public interface SysUserMapper extends BaseMapper { + + /** + * 通过角色ID查询拥有此角色的用户列表 + * + * @param roleId 角色列表 + * @return 拥有此角色的用户列表 + */ + List selectUsersByRoleId(Integer roleId); + + /** + * 通过角色ID查询不拥有此角色的用户列表 + * + * @param roleId 角色列表 + * @return 不拥有此角色的用户列表 + */ + List selectUsersByRoleIdNotIn(Integer roleId); + + List selectUsersByCloudUploadRoleId(@Param("roleId") String roleId); + List selectUsersByCloudUploadRoleIdNotIn(@Param("roleId") String roleId); + + ArrayList queryByPage(@Param("page")Integer pageNo, @Param("size")Integer pageSize, @Param("username") String username,@Param("phone") String phone,@Param("departmentId") String departmentId); + Integer queryByPageCount(@Param("username") String username,@Param("phone") String phone,@Param("departmentId") String departmentId); + + + List selectByIds(@Param("ids") List userIds); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysUserRoleMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..fad6eb7 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,18 @@ +package com.zxdmy.excite.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.SysUserRole; +import org.springframework.stereotype.Repository; + +/** + *

                          + * 系统用户和角色关联表 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2021-09-23 + */ +@Repository +public interface SysUserRoleMapper extends BaseMapper { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/account/CloudCompanyMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/account/CloudCompanyMapper.java new file mode 100644 index 0000000..b35014c --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/account/CloudCompanyMapper.java @@ -0,0 +1,30 @@ +package com.zxdmy.excite.system.mapper.cloud.account; + +import com.zxdmy.excite.system.entity.cloud.account.CloudCompany; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartment; +import com.zxdmy.excite.system.entity.req.account.ReqCompany; +import com.zxdmy.excite.system.entity.vo.account.CompanyVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 企业表 Mapper 接口 + *

                          + * + * @author ss + * @since 2026-01-24z + */ +@Mapper +public interface CloudCompanyMapper extends BaseMapper { + + ArrayList queryByPage(@Param("page")Integer pageNo, @Param("size")Integer pageSize, @Param("data") ReqCompany data); + Integer queryByPageCount(@Param("data") ReqCompany data); + CompanyVo getData(@Param("data") ReqCompany data); + List queryByData(); + List getList(); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/account/CloudDepartmentMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/account/CloudDepartmentMapper.java new file mode 100644 index 0000000..ce95453 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/account/CloudDepartmentMapper.java @@ -0,0 +1,30 @@ +package com.zxdmy.excite.system.mapper.cloud.account; + +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartment; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.req.account.ReqDepartment; +import com.zxdmy.excite.system.entity.vo.account.DepartmentVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 部门表 Mapper 接口 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +@Mapper +public interface CloudDepartmentMapper extends BaseMapper { + ArrayList queryByPage(@Param("page")Integer pageNo, @Param("size")Integer pageSize, @Param("data") ReqDepartment data); + Integer queryByPageCount(@Param("data") ReqDepartment data); + DepartmentVo getData(@Param("data") ReqDepartment data); + List getList(@Param("id") Long id); + + List selectByCompanyId(@Param("companyId") Long companyId); + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/account/CloudDepartmentUserMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/account/CloudDepartmentUserMapper.java new file mode 100644 index 0000000..5646f3a --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/account/CloudDepartmentUserMapper.java @@ -0,0 +1,21 @@ +package com.zxdmy.excite.system.mapper.cloud.account; + +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartmentUser; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

                          + * 部门用户ID Mapper 接口 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +@Mapper +public interface CloudDepartmentUserMapper extends BaseMapper { + List selectByCompanyId(@Param("companyId") Long companyId); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/collection/CloudUserCollectionMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/collection/CloudUserCollectionMapper.java new file mode 100644 index 0000000..c796c63 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/collection/CloudUserCollectionMapper.java @@ -0,0 +1,33 @@ +package com.zxdmy.excite.system.mapper.cloud.collection; + +import com.zxdmy.excite.system.entity.cloud.collection.CloudUserCollection; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.req.account.ReqCompany; +import com.zxdmy.excite.system.entity.req.collection.ReqCloudUserCollection; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.account.CompanyVo; +import com.zxdmy.excite.system.entity.vo.collection.CloudUserCollectionVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.ArrayList; + +/** + *

                          + * 收藏表 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Mapper +public interface CloudUserCollectionMapper extends BaseMapper { + + ArrayList queryByPage(@Param("page")Integer pageNo, @Param("size")Integer pageSize, @Param("data") ReqCloudUserCollection data); + + Integer queryByPageCount(@Param("data") ReqCloudUserCollection data); + + CloudUserCollectionVo getData(@Param("data") ReqCloudUserCollection data); + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/lately/CloudUserLatelyMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/lately/CloudUserLatelyMapper.java new file mode 100644 index 0000000..4b551c0 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/lately/CloudUserLatelyMapper.java @@ -0,0 +1,30 @@ +package com.zxdmy.excite.system.mapper.cloud.lately; + +import com.zxdmy.excite.system.entity.cloud.lately.CloudUserLately; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.req.lately.ReqCloudUserLately; +import com.zxdmy.excite.system.entity.vo.lately.CloudUserLatelyVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.ArrayList; + +/** + *

                          + * 最近文件表 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Mapper +public interface CloudUserLatelyMapper extends BaseMapper { + + ArrayList queryByPage(@Param("page")Integer pageNo, @Param("size")Integer pageSize, @Param("data") ReqCloudUserLately data); + + Integer queryByPageCount(@Param("data") ReqCloudUserLately data); + + CloudUserLatelyVo getData(@Param("data") ReqCloudUserLately data); + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/role/CloudRoleFileMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/role/CloudRoleFileMapper.java new file mode 100644 index 0000000..279d767 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/role/CloudRoleFileMapper.java @@ -0,0 +1,18 @@ +package com.zxdmy.excite.system.mapper.cloud.role; + +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleFile; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + *

                          + * 云盘权限文件表 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2026-02-01 + */ +@Mapper +public interface CloudRoleFileMapper extends BaseMapper { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/role/CloudRoleMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/role/CloudRoleMapper.java new file mode 100644 index 0000000..0a016aa --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/role/CloudRoleMapper.java @@ -0,0 +1,29 @@ +package com.zxdmy.excite.system.mapper.cloud.role; + +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.req.role.ReqRole; +import com.zxdmy.excite.system.entity.vo.role.RoleVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 云盘权限表 Mapper 接口 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +@Mapper +public interface CloudRoleMapper extends BaseMapper { + + ArrayList queryByPage(@Param("page")Integer pageNo, @Param("size")Integer pageSize, @Param("data") ReqRole data); + Integer queryByPageCount(@Param("data") ReqRole data); + RoleVo getData(@Param("data") ReqRole data); + List queryByData(); + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/role/CloudRoleUserMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/role/CloudRoleUserMapper.java new file mode 100644 index 0000000..b2d0d2a --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/role/CloudRoleUserMapper.java @@ -0,0 +1,18 @@ +package com.zxdmy.excite.system.mapper.cloud.role; + +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleUser; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + *

                          + * 云盘权限用户表 Mapper 接口 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +@Mapper +public interface CloudRoleUserMapper extends BaseMapper { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/space/CloudFileMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/space/CloudFileMapper.java new file mode 100644 index 0000000..a46a743 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/space/CloudFileMapper.java @@ -0,0 +1,40 @@ +package com.zxdmy.excite.system.mapper.cloud.space; + +import com.zxdmy.excite.system.entity.cloud.space.CloudFile; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.req.account.ReqCompany; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.account.CompanyVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 文件表 Mapper 接口 + *

                          + * + * @author ss + * @since 2026-01-28 + */ +@Mapper +public interface CloudFileMapper extends BaseMapper { + + ArrayList queryByPage(@Param("page")Integer pageNo, @Param("size")Integer pageSize, @Param("data") ReqCloudFile data); + + Integer queryByPageCount(@Param("data") ReqCloudFile data); + + ArrayList queryByRecyclePage(@Param("page")Integer pageNo, @Param("size")Integer pageSize, @Param("data") ReqCloudFile data); + Integer queryByRecyclePageCount(@Param("data") ReqCloudFile data); + + CloudFileVo getData(@Param("data") ReqCloudFile data); + + ArrayList queryByIndexPage(@Param("page")Integer pageNo, @Param("size")Integer pageSize, @Param("data") ReqCloudFile data); + + Integer queryByIndexPageCount(@Param("data") ReqCloudFile data); + List queryFileByData(@Param("data") ReqCloudFile data); + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/space/CloudFileRoleMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/space/CloudFileRoleMapper.java new file mode 100644 index 0000000..b20a65e --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/space/CloudFileRoleMapper.java @@ -0,0 +1,30 @@ +package com.zxdmy.excite.system.mapper.cloud.space; + +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.cloud.space.CloudFileRole; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.space.CloudFileRoleVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.entity.vo.space.CloudRoleFileVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

                          + * 文件用户权限表 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2026-01-30 + */ +@Mapper +public interface CloudFileRoleMapper extends BaseMapper { + List getFileRole(@Param("id") String id); + List getRoleFile(@Param("id") String id); + List getRoleFileCheck(@Param("id") String id); + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/trace/CloudFileTraceMapper.java b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/trace/CloudFileTraceMapper.java new file mode 100644 index 0000000..42f0179 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/mapper/cloud/trace/CloudFileTraceMapper.java @@ -0,0 +1,28 @@ +package com.zxdmy.excite.system.mapper.cloud.trace; + +import com.zxdmy.excite.system.entity.cloud.trace.CloudFileTrace; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zxdmy.excite.system.entity.req.lately.ReqCloudUserLately; +import com.zxdmy.excite.system.entity.req.trace.ReqCloudFileTrace; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.entity.vo.trace.CloudFileTraceVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.ArrayList; + +/** + *

                          + * 文件痕迹 Mapper 接口 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Mapper +public interface CloudFileTraceMapper extends BaseMapper { + + ArrayList queryByPage(@Param("page")Integer pageNo, @Param("size")Integer pageSize, @Param("data") ReqCloudFileTrace data); + + Integer queryByPageCount(@Param("data") ReqCloudFileTrace data); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysLogLoginService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysLogLoginService.java new file mode 100644 index 0000000..e48d3bc --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysLogLoginService.java @@ -0,0 +1,20 @@ +package com.zxdmy.excite.system.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zxdmy.excite.system.entity.SysLogLogin; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

                          + * 服务类 + *

                          + * + * @author 沈松 + * @since 2021-12-28 + */ +public interface ISysLogLoginService extends IService { + + Page getPage(Integer current, Integer size,String userId, String ip,String startDate, String endDate); + + int deleteLog(Integer[] logIds); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysLogRequestService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysLogRequestService.java new file mode 100644 index 0000000..23b22b6 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysLogRequestService.java @@ -0,0 +1,20 @@ +package com.zxdmy.excite.system.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zxdmy.excite.system.entity.SysLogRequest; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

                          + * 服务类 + *

                          + * + * @author 沈松 + * @since 2021-12-09 + */ +public interface ISysLogRequestService extends IService { + + Page getPage(Integer current, Integer size, String userId, String startDate, String endDate); + + int deleteLog(Integer[] logIds); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysMenuService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysMenuService.java new file mode 100644 index 0000000..bc5452f --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysMenuService.java @@ -0,0 +1,107 @@ +package com.zxdmy.excite.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.SysMenu; + + +import java.util.List; + +/** + *

                          + * 系统菜单/权限表 服务类 + *

                          + * + * @author 沈松 + * @since 2021-09-12 + */ +public interface ISysMenuService extends IService { + + + /** + * 添加或更新一个菜单/权限 + * 使用接口:新增接口、编辑接口 + * + * @param menu 菜单/权限 实体 + * @return 影响的行数 0-失败 | 1-成功 + */ + public int saveMenu(SysMenu menu); + + /** + * 修改菜单的状态 + * 使用接口:修改菜单状态接口 + * + * @param newStatus 新状态 + * @return 影响的行数 0-失败 | 1-成功 + */ + public int[] changeStatus(int newStatus, Integer[] menuIds); + + /** + * 获取一个菜单/权限 + * 使用接口:编辑接口(读取当前编辑的菜单详情) + * + * @param id 菜单/权限的ID + * @return 菜单实体 + */ + public SysMenu getMenu(Integer id); + + /** + * 获取菜单/权限列表 + * + * @param isAll True:返回全部 | false:只返回目录+菜单 + * @return 菜单实体列表 + */ + public List getMenuList(Boolean isAll); + + /** + * 删除一个菜单/权限 + * + * @param id 菜单/权限的ID + * @return 影响的行数 0-失败 | 1-成功 + */ + public int deleteMenu(Integer id); + + /** + * 通过角色ID查询全部菜单列表 + * 使用接口:角色管理---编辑角色,用于加载当前角色已经选中的菜单权限 + * + * @param roleId 角色ID。若为0,表示不指定角色ID。 + * @return 全部菜单列表 + */ + public List getMenuListForRole(int roleId); + + + /** + * 通过用户的ID获取权限列表 + * + * @param userId 用户ID + * @param userId 用户ID * @param isOnlyMenu 是否只获取菜单(不含按钮) + * @return 菜单/权限列表 + */ + public List getMenuListByUserId(Integer userId, boolean isOnlyMenu); + + /** + * 通过角色的ID查询该角色拥有的菜单/权限 + * + * @param roleId 角色ID + * @return 菜单/权限列表 + */ + public List getMenuListByRoleId(Integer roleId); + + + /** + * 认证框架使用:权限管理模块使用到的获取权限列表 + * + * @return 菜单权限列表 + */ + public List getMenuListForSaToken(); + + /** + * 认证框架使用:通过用户ID获取该用户所拥有的权限 + * + * @param userId 用户ID + * @return 菜单权限列表 + */ + public List getMenuListByUserIdForSaToken(Integer userId); + + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysRoleMenuService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysRoleMenuService.java new file mode 100644 index 0000000..cfc9fa9 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysRoleMenuService.java @@ -0,0 +1,17 @@ +package com.zxdmy.excite.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.SysRoleMenu; + + +/** + *

                          + * 系统角色和菜单/权限关联表 服务类 + *

                          + * + * @author 沈松 + * @since 2021-09-16 + */ +public interface ISysRoleMenuService extends IService { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysRoleService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysRoleService.java new file mode 100644 index 0000000..c2bb401 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysRoleService.java @@ -0,0 +1,90 @@ +package com.zxdmy.excite.system.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.SysRole; + + +import java.util.List; + +/** + *

                          + * 系统角色表 服务类 + *

                          + * + * @author 沈松 + * @since 2021-09-23 + */ +public interface ISysRoleService extends IService { + + /** + * 接口:添加|更新角色 + * + * @param role 角色实体,ID为空表示添加 + * @param menusIds 为当前角色添加的菜单/权限ID列表 + * @return 影响的行数 0 - 失败 | >0 - 成功 + */ + public int saveRole(SysRole role, Integer[] menusIds); + + /** + * 接口:根据ID查询某个角色详情 + * + * @param id 角色的ID + * @return 角色实体 + */ + public SysRole getRole(Integer id); + + /** + * 接口:查询状态正常的角色列表 + * + * @return 角色列表 + */ + public List getListByUserId(Integer userId); + + /** + * 接口:分页查询接口列表 + * + * @param current 当前页 + * @param size 页大小 + * @param name 检索:名称 + * @param permission 检索:权限字符 + * @return 结果页面 + */ + public Page getPage(Integer current, Integer size, String name, String permission); + + /** + * 接口:修改角色状态 + * + * @param newStatus 新状态 + * @param roleIds 角色ID列表 + * @return 结果 + */ + public int[] changeStatus(Integer newStatus, Integer[] roleIds); + + /** + * 接口:删除角色 + * + * @param roleIds 角色ID数组 + * @return 删除结果:0:成功个数 1:删除失败个数 2:因已分配用户,禁止删除数 + */ + public int[] deleteRoleById(Integer[] roleIds); + + + /** + * 接口:将指定角色,授权分配给系列用户 + * + * @param roleId 角色ID + * @param userIds 用户ID列表 + * @return 授权结果 + */ + public boolean authRoleForUsers(Integer roleId, Integer[] userIds); + + /** + * 接口:取消指定角色已授权的系列用户 + * + * @param roleId 角色ID + * @param userIds 用户ID列表 + * @return 取消授权结果 + */ + public int[] revokeRoleForUsers(Integer roleId, Integer[] userIds); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysUserRoleService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysUserRoleService.java new file mode 100644 index 0000000..641c950 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysUserRoleService.java @@ -0,0 +1,34 @@ +package com.zxdmy.excite.system.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.SysUserRole; + +import java.util.List; + +/** + *

                          + * 系统用户和角色关联表 服务类 + *

                          + * + * @author 沈松 + * @since 2021-09-23 + */ +public interface ISysUserRoleService extends IService { + + /** + * 通过角色ID获取用户角色关联列表 + * + * @param roleId 角色ID + * @return 用户角色关联列表 + */ + public List getListByRoleId(Integer roleId); + + /** + * 通过用户ID获取用户角色关联列表 + * + * @param userId 用户ID + * @return 用户角色关联列表 + */ + public List getListByUserId(Integer userId); + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysUserService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysUserService.java new file mode 100644 index 0000000..4b6854c --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/ISysUserService.java @@ -0,0 +1,101 @@ +package com.zxdmy.excite.system.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.req.account.ReqDepartment; +import com.zxdmy.excite.system.entity.vo.account.DepartmentVo; + +import java.util.List; + +/** + *

                          + * 系统用户表 服务类 + *

                          + * + * @author 沈松 + * @since 2021-09-01 + */ +public interface ISysUserService extends IService { + + /** + * 登录服务 + * + * @param username 用户名 + * @param password 密码 + * @return SysUser:登录成功 | null:登录失败 + */ + public SysUser login(String username, String password); + + + /** + * 获取用户列表 + * + * @param current 当前页 + * @param size 当前页大小 + * @param username 检索用户名 + * @param account 检索邮箱/手机号 + * @return 用户页面信息 + */ + public Page getPage(Integer current, Integer size, String username, String account); + + PageList queryByPage(Integer current, Integer size, String username, String phone,String departmentId); + + /** + * 保存用户:添加 | 更新 + * + * @param user 用户信息 + * @param roleIds 角色ID列表 + * @return 修改的行数 >0:成功 | <=0:失败 + */ + public int save(SysUser user, Integer[] roleIds); + + public int saveData(SysUser user, Integer[] roleIds,String[] roleIds1,String departmentId); + /** + * 接口:修改用户状态 + * + * @param newStatus 新状态 + * @param userIds 用户ID列表 + * @return 修改结果数组 0:成功个数 1:失败个数 + */ + public int[] changeStatus(Integer newStatus, Integer[] userIds); + + /** + * 接口:给用户分配角色 + * + * @param userId 用户ID + * @param roleIds 角色ID数组 + * @return 修改结果数组 0:分配个数 1:失败个数 + */ + public boolean setRoleForUser(Integer userId, Integer[] roleIds); + + public boolean setCloudRoleForUser(String userId, String[] roleIds); + + /** + * 接口:根据ID删除用户 + * + * @param userId 用户ID + * @return 删除结果:>0 表示成功 + */ + int[] deleteUserById(Integer[] userId); + + /** + * 接口:通过角色ID查询用户列表 + * + * @param roleId 角色ID + * @return 用户列表 + */ + List getUserListByRoleId(Integer roleId); + + /** + * 接口:通过角色ID查询不包含此角色的用户列表 + * + * @param roleId 角色ID + * @return 不包含此角色的用户列表 + */ + List getUserListByRoleIdNotIn(Integer roleId); + + List selectUsersByCloudUploadRoleId(String roleId); + List selectUsersByCloudUploadRoleIdNotIn(String roleId); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/account/ICloudCompanyService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/account/ICloudCompanyService.java new file mode 100644 index 0000000..124eded --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/account/ICloudCompanyService.java @@ -0,0 +1,28 @@ +package com.zxdmy.excite.system.service.cloud.account; + +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.system.entity.cloud.account.CloudCompany; +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartment; +import com.zxdmy.excite.system.entity.req.account.ReqCompany; +import com.zxdmy.excite.system.entity.vo.account.CompanyVo; + +import java.util.List; + +/** + *

                          + * 企业表 服务类 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +public interface ICloudCompanyService extends IService { + PageList queryByPage(Integer current, Integer size, ReqCompany data); + CompanyVo getByData(ReqCompany data); + int saveData(ReqCompany data); + int updateData(ReqCompany data); + int deleteById(String id); + List queryByData(); + List getList(); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/account/ICloudDepartmentService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/account/ICloudDepartmentService.java new file mode 100644 index 0000000..1f638c3 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/account/ICloudDepartmentService.java @@ -0,0 +1,31 @@ +package com.zxdmy.excite.system.service.cloud.account; + +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartment; +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.dto.DepartmentUserTreeNode; +import com.zxdmy.excite.system.entity.req.account.ReqDepartment; +import com.zxdmy.excite.system.entity.vo.account.DepartmentVo; + +import java.util.List; + +/** + *

                          + * 部门表 服务类 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +public interface ICloudDepartmentService extends IService { + + PageList queryByPage(Integer current, Integer size, ReqDepartment data); + DepartmentVo getByData(ReqDepartment data); + int saveData(ReqDepartment data); + int updateData(ReqDepartment data); + int deleteById(String id); + List getList(Long id); + int changeDepartment(String userId, String departmentId); + + public List buildDepartmentUserTree(Long companyId); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/account/ICloudDepartmentUserService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/account/ICloudDepartmentUserService.java new file mode 100644 index 0000000..cbd3ec6 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/account/ICloudDepartmentUserService.java @@ -0,0 +1,16 @@ +package com.zxdmy.excite.system.service.cloud.account; + +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartmentUser; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

                          + * 部门用户ID 服务类 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +public interface ICloudDepartmentUserService extends IService { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/collection/ICloudUserCollectionService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/collection/ICloudUserCollectionService.java new file mode 100644 index 0000000..78f1c66 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/collection/ICloudUserCollectionService.java @@ -0,0 +1,29 @@ +package com.zxdmy.excite.system.service.cloud.collection; + +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.system.entity.cloud.collection.CloudUserCollection; +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.req.account.ReqCompany; +import com.zxdmy.excite.system.entity.req.collection.ReqCloudUserCollection; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.account.CompanyVo; +import com.zxdmy.excite.system.entity.vo.collection.CloudUserCollectionVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; + +/** + *

                          + * 收藏表 服务类 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +public interface ICloudUserCollectionService extends IService { + + PageList queryByPage(Integer current, Integer size, ReqCloudUserCollection data); + + CloudUserCollectionVo getByData(ReqCloudUserCollection data); + + int saveData(ReqCloudUserCollection data); + int deleteById(String id); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/lately/ICloudUserLatelyService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/lately/ICloudUserLatelyService.java new file mode 100644 index 0000000..a1fd5df --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/lately/ICloudUserLatelyService.java @@ -0,0 +1,27 @@ +package com.zxdmy.excite.system.service.cloud.lately; + +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.system.entity.cloud.lately.CloudUserLately; +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.req.collection.ReqCloudUserCollection; +import com.zxdmy.excite.system.entity.req.lately.ReqCloudUserLately; +import com.zxdmy.excite.system.entity.vo.collection.CloudUserCollectionVo; +import com.zxdmy.excite.system.entity.vo.lately.CloudUserLatelyVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; + +/** + *

                          + * 最近文件表 服务类 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +public interface ICloudUserLatelyService extends IService { + + PageList queryByPage(Integer current, Integer size, ReqCloudUserLately data); + CloudUserLatelyVo getByData(ReqCloudUserLately data); + int saveData(ReqCloudUserLately data); + int deleteById(String id); + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/role/ICloudRoleFileService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/role/ICloudRoleFileService.java new file mode 100644 index 0000000..58b91c8 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/role/ICloudRoleFileService.java @@ -0,0 +1,16 @@ +package com.zxdmy.excite.system.service.cloud.role; + +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleFile; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

                          + * 云盘权限文件表 服务类 + *

                          + * + * @author 沈松 + * @since 2026-02-01 + */ +public interface ICloudRoleFileService extends IService { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/role/ICloudRoleService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/role/ICloudRoleService.java new file mode 100644 index 0000000..185e5cd --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/role/ICloudRoleService.java @@ -0,0 +1,36 @@ +package com.zxdmy.excite.system.service.cloud.role; + +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.system.entity.SysRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.req.role.ReqRole; +import com.zxdmy.excite.system.entity.vo.role.RoleVo; + +import java.util.List; + +/** + *

                          + * 云盘权限表 服务类 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +public interface ICloudRoleService extends IService { + + PageList queryByPage(Integer current, Integer size, ReqRole data); + RoleVo getByData(ReqRole data); + int saveData(ReqRole data); + int updateData(ReqRole data); + int deleteById(String id); + public int[] changeUploadStatus(Integer newStatus, String[] ids); + public int[] changeDownStatus(Integer newStatus, String[] ids); + public int[] changeDeleteStatus(Integer newStatus, String[] ids); + public boolean authRoleForUsers(String roleId, String[] userIds); + public int[] revokeRoleForUsers(String roleId, String[] userIds); + + public List getListByUserId(Integer userId); + List queryByData(); + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/role/ICloudRoleUserService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/role/ICloudRoleUserService.java new file mode 100644 index 0000000..a360e96 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/role/ICloudRoleUserService.java @@ -0,0 +1,24 @@ +package com.zxdmy.excite.system.service.cloud.role; + +import com.zxdmy.excite.system.entity.SysUserRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleUser; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + *

                          + * 云盘权限用户表 服务类 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +public interface ICloudRoleUserService extends IService { + + public List getListByUserId(Integer userId); + + CloudRole getCloudShareRole(Integer id); + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/space/ICloudFileRoleService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/space/ICloudFileRoleService.java new file mode 100644 index 0000000..0f8c023 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/space/ICloudFileRoleService.java @@ -0,0 +1,28 @@ +package com.zxdmy.excite.system.service.cloud.space; + +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.cloud.space.CloudFileRole; +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFileRole; +import com.zxdmy.excite.system.entity.vo.space.CloudFileRoleVo; +import com.zxdmy.excite.system.entity.vo.space.CloudRoleFileVo; + +import java.util.List; + +/** + *

                          + * 文件用户权限表 服务类 + *

                          + * + * @author 沈松 + * @since 2026-01-30 + */ +public interface ICloudFileRoleService extends IService { + + List getFileRole(String id); + List getRoleFile(String id); + List getRoleFileCheck(String id); + + CloudFileRole getData(ReqCloudFileRole data); + List getFileRoleByUseId(Integer id); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/space/ICloudFileService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/space/ICloudFileService.java new file mode 100644 index 0000000..c32a193 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/space/ICloudFileService.java @@ -0,0 +1,42 @@ +package com.zxdmy.excite.system.service.cloud.space; + +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.system.entity.cloud.space.CloudFile; +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.req.account.ReqCompany; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.account.CompanyVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; + +import java.util.List; + +/** + *

                          + * 文件表 服务类 + *

                          + * + * @author ss + * @since 2026-01-28 + */ +public interface ICloudFileService extends IService { + + PageList queryByPage(Integer current, Integer size, ReqCloudFile data); + + PageList queryByRecyclePage(Integer current, Integer size, ReqCloudFile data); + + CloudFileVo getByData(ReqCloudFile data); + + int saveData(ReqCloudFile data); + int saveFileData(ReqCloudFile data); + int updateFileData(ReqCloudFile data); + int updateData(ReqCloudFile data); + int recover(String id); + int deleteById(String id); + + public int[] changeDeleteStatus(Integer newStatus, String[] ids); + + PageList queryByIndexPage(Integer current, Integer size, ReqCloudFile data); + + + List queryFileByData(ReqCloudFile data); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/trace/ICloudFileTraceService.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/trace/ICloudFileTraceService.java new file mode 100644 index 0000000..db0e24b --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/cloud/trace/ICloudFileTraceService.java @@ -0,0 +1,22 @@ +package com.zxdmy.excite.system.service.cloud.trace; + +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.system.entity.cloud.trace.CloudFileTrace; +import com.baomidou.mybatisplus.extension.service.IService; +import com.zxdmy.excite.system.entity.req.lately.ReqCloudUserLately; +import com.zxdmy.excite.system.entity.req.trace.ReqCloudFileTrace; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.entity.vo.trace.CloudFileTraceVo; + +/** + *

                          + * 文件痕迹 服务类 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +public interface ICloudFileTraceService extends IService { + PageList queryByPage(Integer current, Integer size, ReqCloudFileTrace data); + int saveData(ReqCloudFileTrace data); +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysLogLoginServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysLogLoginServiceImpl.java new file mode 100644 index 0000000..b10796c --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysLogLoginServiceImpl.java @@ -0,0 +1,52 @@ +package com.zxdmy.excite.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zxdmy.excite.system.entity.SysLogLogin; +import com.zxdmy.excite.system.entity.SysLogRequest; +import com.zxdmy.excite.system.mapper.SysLogLoginMapper; +import com.zxdmy.excite.system.service.ISysLogLoginService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +/** + *

                          + * 服务实现类 + *

                          + * + * @author 沈松 + * @since 2021-12-28 + */ +@Service +@AllArgsConstructor +public class SysLogLoginServiceImpl extends ServiceImpl implements ISysLogLoginService { + + + SysLogLoginMapper loginMapper; + + @Override + public Page getPage(Integer current, Integer size, String userId, String ip, String startDate, String endDate) { + // 页码信息 + current = null == current ? 1 : current; + size = null == size ? 10 : size; + QueryWrapper wrapper = new QueryWrapper<>(); + // 检索请求用户 + wrapper.like(userId != null && !"".equals(userId), "user_id", userId) + // 检索IP + .like(ip != null && !"".equals(ip), "ip", ip) + // 检索起始时间 + .ge(startDate != null && !"".equals(startDate), "create_time", startDate) + // 检索终止时间 + .le(endDate != null && !"".equals(endDate), "create_time", endDate) + .orderByDesc("id"); + return loginMapper.selectPage(new Page<>(current, size), wrapper); + } + + @Override + public int deleteLog(Integer[] logIds) { + return loginMapper.deleteBatchIds(Arrays.asList(logIds)); + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysLogRequestServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysLogRequestServiceImpl.java new file mode 100644 index 0000000..83c62e6 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysLogRequestServiceImpl.java @@ -0,0 +1,50 @@ +package com.zxdmy.excite.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zxdmy.excite.system.entity.SysLogRequest; +import com.zxdmy.excite.system.entity.SysMenu; +import com.zxdmy.excite.system.mapper.SysLogRequestMapper; +import com.zxdmy.excite.system.service.ISysLogRequestService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +/** + *

                          + * 服务实现类 + *

                          + * + * @author 沈松 + * @since 2021-12-09 + */ +@Service +@AllArgsConstructor +public class SysLogRequestServiceImpl extends ServiceImpl implements ISysLogRequestService { + + SysLogRequestMapper logRequestMapper; + + @Override + public Page getPage(Integer current, Integer size, String userId, String startDate, String endDate) { + // 页码信息 + current = null == current ? 1 : current; + size = null == size ? 10 : size; + // 检索信息 + QueryWrapper wrapper = new QueryWrapper<>(); + // 检索请求用户 + wrapper.like(userId != null && !"".equals(userId), "user_id", userId) + // 检索起始时间 + .ge(startDate != null && !"".equals(startDate), "create_time", startDate) + // 检索终止时间 + .le(endDate != null && !"".equals(endDate), "create_time", endDate) + .orderByDesc("id"); + return logRequestMapper.selectPage(new Page<>(current, size), wrapper); + } + + @Override + public int deleteLog(Integer[] logIds) { + return logRequestMapper.deleteBatchIds(Arrays.asList(logIds)); + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysMenuServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000..f5a13dd --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,389 @@ +package com.zxdmy.excite.system.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import com.zxdmy.excite.common.config.ExciteConfig; +import com.zxdmy.excite.common.enums.SystemCode; + +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.common.service.RedisService; +import com.zxdmy.excite.system.entity.SysMenu; +import com.zxdmy.excite.system.entity.SysRoleMenu; +import com.zxdmy.excite.system.mapper.SysMenuMapper; +import com.zxdmy.excite.system.mapper.SysRoleMenuMapper; +import com.zxdmy.excite.system.service.ISysMenuService; + +import com.zxdmy.excite.system.utils.AuthUtils; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + *

                          + * 系统菜单/权限表 服务实现类 + *

                          + * + * @author 沈松 + * @since 2021-09-12 + */ +@Service +@AllArgsConstructor +public class SysMenuServiceImpl extends ServiceImpl implements ISysMenuService { + + + SysMenuMapper menuMapper; + + SysRoleMenuMapper roleMenuMapper; + + RedisService redisService; + + ExciteConfig exciteConfig; + + /** + * 获取一个菜单/权限 + * 使用接口:编辑接口(读取当前编辑的菜单详情) + * + * @param id 菜单/权限的ID + * @return 菜单实体 + */ + @Override + public SysMenu getMenu(Integer id) { + if (null == id) { + throw new ServiceException("服务错误:菜单/权限的ID不能为null"); + } + QueryWrapper wrapper = new QueryWrapper<>(); + // 根据ID查询status正常的菜单 + wrapper.eq("id", id).ne("status", SystemCode.STATUS_N.getCode()); + return menuMapper.selectOne(wrapper); + } + + /** + * 添加或更新一个菜单/权限 + * 使用接口:新增接口、编辑接口 + * + * @param menu 菜单/权限 实体 + * @return 影响的行数 0-失败 | 1-成功 + */ + @Override + public int saveMenu(SysMenu menu) { + if (null == menu) { + throw new ServiceException("服务错误:菜单/权限为空"); + } + // 根据ID判断是否是新增,ID为空是新增,否则是更新 + boolean isAdd = null == menu.getId(); + // 如果是顶级菜单:上级菜单为-1,请求路径为"" + if ("N".equals(menu.getType())) { + menu.setParentId(-1); + menu.setPath(""); + } + // 如果是目录:请求路径设置为空字符串(非NULL) + else if ("C".equals(menu.getType())) { + menu.setPath(""); + } + // 初始化:标签 + if (!"fa ".equals(menu.getIcon().substring(0, 3))) + menu.setIcon("fa " + menu.getIcon()); + // 如果未输入排序,则填充默认顺序:50 + if (null == menu.getSort()) { + menu.setSort(SystemCode.SORT_DEFAULT.getCode()); + } + // 设置时间信息 + LocalDateTime localDateTime = LocalDateTime.now(); + int result = 0; + // 新增 + if (isAdd) { + menu.setCreateTime(localDateTime); + // 设置初始状态:正常 + if (null == menu.getStatus()) { + menu.setStatus(SystemCode.STATUS_Y.getCode()); + } + if (null == menu.getEditable()) { + menu.setEditable(SystemCode.EDITABLE_Y.getCode()); + } + if (null == menu.getRemovable()) { + menu.setRemovable(SystemCode.REMOVABLE_Y.getCode()); + } + result = menuMapper.insert(menu); + // 清除缓存 + AuthUtils.clearSystemMenuListCache(result != 0); + } + // 修改 + else { + menu.setUpdateTime(localDateTime); + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("id", menu.getId()) + .eq("editable", SystemCode.EDITABLE_Y.getCode()) + .ne("status", SystemCode.STATUS_N.getCode()); + result = menuMapper.update(menu, wrapper); + // 清除缓存 + AuthUtils.clearSystemMenuListCache(result != 0); + AuthUtils.clearUserMenuListCache(result != 0); + } + return result; + } + + /** + * 修改菜单的状态 + * 使用接口:修改菜单状态接口 + * + * @return 影响的行数 0-失败 | 1-成功 + */ + @Override + public int[] changeStatus(int newStatus, Integer[] menuIds) { + int[] result = new int[2]; + for (Integer menuId : menuIds) { + SysMenu menu = new SysMenu(); + QueryWrapper wrapper = new QueryWrapper<>(); + menu.setId(menuId); + menu.setStatus(newStatus); + wrapper.eq("id", menuId) + .ne("status", SystemCode.STATUS_Y_BLOCK.getCode()); + if (menuMapper.update(menu, wrapper) > 0) + result[0]++; + else result[1]++; + } + // 清除缓存 + AuthUtils.clearUserMenuListCache(result[0] != 0); + return result; + } + + /** + * 获取菜单/权限列表 + * 使用接口: + * + * @param isAll True:返回全部 | false:只返回目录+菜单 + * @return 菜单实体列表 + */ + @Override + public List getMenuList(Boolean isAll) { + QueryWrapper wrapper = new QueryWrapper<>(); + // 查询状态status正常(0)的菜单 + wrapper.ne(!isAll, "status", SystemCode.STATUS_N.getCode()) + // 非只查询菜单,则【排除】类型(type)是按钮(B)的权限 + .ne(!isAll, "type", "B") + // 排序 + .orderByDesc("sort"); + return menuMapper.selectList(wrapper); + } + + /** + * 删除一个菜单/权限 + * 使用接口:删除菜单 + * + * @param id 菜单/权限的ID + * @return 影响的行数 0-失败 | 1-成功 + */ + @Override + public int deleteMenu(Integer id) { + if (id == null) { + throw new ServiceException("服务错误:菜单/权限的ID不能为null"); + } + // 这里注意:menu表和roleMenu表未设置关联,所以可以先删除菜单,再删除关联。 + // 如果二者设置了外键关联,则流程是:判断menu可删除-->删除roleMenu关联-->删除menu + // 只有removable=1的菜单才可以删除 + QueryWrapper wrapper2 = new QueryWrapper<>(); + wrapper2.eq("id", id) + .ne("status", SystemCode.STATUS_N.getCode()) + .eq("removable", SystemCode.REMOVABLE_Y.getCode()); + int result = menuMapper.delete(wrapper2); + // 当删除一个菜单后,需要从【角色-权限关联表】中删除含有该菜单的记录 + if (result > 0) { + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("menu_id", id); + roleMenuMapper.delete(wrapper1); + } + // 清除缓存 + AuthUtils.clearSystemMenuListCache(result != 0); + AuthUtils.clearUserMenuListCache(result != 0); + return result; + } + + /** + * 外部接口:通过角色ID查询菜单 + * + * @param roleId 角色ID。若为0,表示不指定角色ID。 + * @return 菜单列表 + */ + @Override + public List getMenuListForRole(int roleId) { + // 获取全部的菜单 + QueryWrapper sysMenuQueryWrapper = new QueryWrapper<>(); + sysMenuQueryWrapper.ne("status", SystemCode.STATUS_N.getCode()) + .orderByDesc("sort"); + List menuList = menuMapper.selectList(sysMenuQueryWrapper); + // 如果为roleId=0,表示获取全部正常的菜单 + if (0 == roleId) { + return menuList; + } + // 否则,获取全部菜单后,将该角色拥有的菜单的CheckArr字段标记为1 + else { + // 获取当前角色拥有的权限 + QueryWrapper roleMenuQueryWrapper = new QueryWrapper<>(); + roleMenuQueryWrapper.eq("role_id", roleId); + List roleMenuList = roleMenuMapper.selectList(roleMenuQueryWrapper).stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList()); + // 使用lambda表达式,直接在菜单列表上修改checkArr字段 + return menuList.stream().peek(menu -> { + if (roleMenuList.contains(menu.getId())) + menu.setCheckArr("1"); + }).collect(Collectors.toList()); + } + } + + + /** + * 接口实现:通过用户ID查询该用户所拥有的菜单(不含角色、菜单被禁用的菜单权限) + * + * @param userId 用户ID + * @param isOnlyMenu 是否只获取菜单(不含按钮) + * @return 菜单列表 + */ + @Override + public List getMenuListByUserId(Integer userId, boolean isOnlyMenu) { + // 只获取菜单列表 + if (isOnlyMenu) { + return menuMapper.selectMenusByUserId(userId, 1); + } + // 获取菜单+权限列表 + else { + return menuMapper.selectMenusByUserId(userId, 0); + } + } + + /** + * 接口实现:通过角色的ID查询该角色拥有的菜单/权限(不含菜单被禁用的菜单权限) + * + * @param roleId 角色ID + * @return 菜单/权限列表 + */ + @Override + public List getMenuListByRoleId(Integer roleId) { + return menuMapper.selectMenusByRoleId(roleId); + } + + /** + * 内部调用:获取所有的菜单/权限列表,为权限认证框架使用 + * + * @return 菜单实体列表 + */ + @Override + public List getMenuListForSaToken() { + // 首先尝试从缓存中读取数据 + List menuList = AuthUtils.getSystemMenuListCache(true); + // 如果未命中缓存:从缓存读取 + if (null == menuList) { + menuList = menuMapper.selectList(null); + // 同时尝试写入缓存 + AuthUtils.setSystemMenuListCache(null != menuList, menuList); + } + return menuList; + } + + + /** + * 内部调用:获取指定用户的菜单/权限列表,为权限认证框架使用 + * + * @param userId 用户ID + * @return 菜单权限列表 + */ + @Override + public List getMenuListByUserIdForSaToken(Integer userId) { + // 先尝试从缓存读取 + List menuList = AuthUtils.getUserMenuListCache(true, userId); + // 如果为空,则从数据库读取 + if (null == menuList) { + menuList = this.getMenuListByUserId(userId, false); + // 同时尝试写入缓存 + AuthUtils.setUserMenuListCache(null != menuList, userId, menuList); + } + return menuList; + } + +// /** +// * 将最新的全部菜单列表保存至Redis数据库 +// * 因为:对菜单基础信息进行增、改、删等操作后,如果开启Redis缓存,需要将Redis中的数据进行更新 +// * +// * @param result 执行增改删的结果 +// */ +// private List saveAllMenu2Redis(int result) { +// // 如果开启Redis,并且Redis服务正常 +// if (result > 0 && exciteConfig.getAllowRedis()) { +// QueryWrapper wrapper = new QueryWrapper<>(); +// // 查询全部菜单(无论禁用与否) +// wrapper.orderByDesc("sort"); +// List menuList = menuMapper.selectList(wrapper); +// if (null != menuList) { +// redisService.set("menu:allMenuList", (Serializable) menuList); +// } +// // 同时删除全部Redis中保存的用户 +// Set userSet = (Set) redisService.get("menu:userList"); +// if (userSet != null) { +// for (Integer userId : userSet) { +// redisService.remove("menu:userMenuList:" + userId); +// } +// redisService.remove("menu:userList"); +// } +// return menuList; +// } +// return null; +// } +// +// /** +// * 从Redis数据库中读取全部的菜单信息 +// * +// * @return 菜单列表 +// */ +// private List getAllMenu4Redis() { +// // 如果开启Redis,则从redis中读取 +// if (exciteConfig.getAllowRedis()) { +// // redis中没有:存入并返回 +// if (!redisService.hasKey("menu:allMenuList")) { +// return this.saveAllMenu2Redis(1); +// } +// // redis中有:返回 +// return (List) redisService.get("menu:allMenuList"); +// } +// // 未开启redis,返回 +// return null; +// } +// +// /** +// * 私有方法:从redis中读取 保存当前用户的权限菜单列表至redis +// * 同时将已经保存至redis的用户集合更新 +// * +// * @param userId 用户ID +// * @return 当前用户的权限列表 +// */ +// private List getUserMenu4Redis(Integer userId) { +// // 如果开启Redis,则从redis中读取 +// if (exciteConfig.getAllowRedis()) { +// // redis中没有: +// if (!redisService.hasKey("menu:userMenuList:" + userId)) { +// // 存入并返回 +// List menuList = menuMapper.selectMenusByUserId(userId, 0); +// if (null != menuList) { +// redisService.set("menu:userMenuList:" + userId, (Serializable) menuList); +// Set userSet = new HashSet<>(); +// // 同时把该用户的ID存入Redis +// if (redisService.hasKey("menu:userList")) { +// userSet = (Set) redisService.get("menu:userList"); +// } +// userSet.add(userId); +// redisService.set("menu:userList", (Serializable) userSet); +// } +// return menuList; +// } +// // redis中有:返回 +// return (List) redisService.get("menu:userMenuList:" + userId); +// } +// // 未开启redis,返回空 +// return null; +// } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysRoleMenuServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysRoleMenuServiceImpl.java new file mode 100644 index 0000000..c03601e --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysRoleMenuServiceImpl.java @@ -0,0 +1,20 @@ +package com.zxdmy.excite.system.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zxdmy.excite.system.entity.SysRoleMenu; +import com.zxdmy.excite.system.mapper.SysRoleMenuMapper; +import com.zxdmy.excite.system.service.ISysRoleMenuService; +import org.springframework.stereotype.Service; + +/** + *

                          + * 系统角色和菜单/权限关联表 服务实现类 + *

                          + * + * @author 沈松 + * @since 2021-09-16 + */ +@Service +public class SysRoleMenuServiceImpl extends ServiceImpl implements ISysRoleMenuService { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysRoleServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000..c506306 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,361 @@ +package com.zxdmy.excite.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zxdmy.excite.common.config.ExciteConfig; +import com.zxdmy.excite.common.enums.SystemCode; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.common.service.RedisService; +import com.zxdmy.excite.system.entity.SysMenu; +import com.zxdmy.excite.system.entity.SysRole; +import com.zxdmy.excite.system.entity.SysRoleMenu; +import com.zxdmy.excite.system.entity.SysUserRole; +import com.zxdmy.excite.system.mapper.SysRoleMapper; +import com.zxdmy.excite.system.service.ISysRoleMenuService; +import com.zxdmy.excite.system.service.ISysRoleService; +import com.zxdmy.excite.system.service.ISysUserRoleService; + + +import com.zxdmy.excite.system.utils.AuthUtils; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + *

                          + * 系统角色表 服务实现类 + *

                          + * + * @author 沈松 + * @since 2021-09-23 + */ +@Service +@AllArgsConstructor +public class SysRoleServiceImpl extends ServiceImpl implements ISysRoleService { + + SysRoleMapper roleMapper; + + ISysRoleMenuService roleMenuService; + + ISysUserRoleService userRoleService; + + RedisService redisService; + + ExciteConfig exciteConfig; + + /** + * 接口实现:添加|更新角色 + * + * @param role 角色实体,ID为空表示添加 + * @param menusIds 为当前角色添加的菜单/权限ID列表 + * @return 影响的行数 0 - 失败 | >0 - 成功 + */ + @Override + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) + public int saveRole(SysRole role, Integer[] menusIds) { + if (null == role) { + throw new ServiceException("角色实体不能为null"); + } + // 初始化:角色状态 + if (null == role.getStatus()) { + role.setStatus(SystemCode.STATUS_Y.getCode()); + } + // 初始化:角色顺序 + if (null == role.getSort()) { + role.setStatus(SystemCode.SORT_DEFAULT.getCode()); + } + LocalDateTime localDateTime = LocalDateTime.now(); + int result = 0; + // 新增 + if (null == role.getId()) { + role.setCreateTime(localDateTime); + role.setIsDelete(SystemCode.DELETE_N.getCode()); + // 先插入角色,以便获取角色的ID + result = roleMapper.insert(role); + if (result > 0) { + // 插入权限关联列表 + insertRoleMenu(role.getId(), menusIds); + } + } + // 更新 + else { + role.setUpdateTime(localDateTime); + // 将新菜单插入 + result = roleMapper.updateById(role); + if (result > 0) { + // 先从关联表中删除旧数据 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("role_id", role.getId()); + roleMenuService.remove(wrapper1); + // 再添加新数据 + insertRoleMenu(role.getId(), menusIds); + } + // 清除缓存 + AuthUtils.clearUserMenuListCache(result != 0); + } + return result; + } + + /** + * 接口实现:根据ID查询某个角色详情 + * + * @param id 角色的ID + * @return 角色实体 + */ + @Override + public SysRole getRole(Integer id) { + if (null == id) { + throw new ServiceException("角色ID不能为null"); + } + // 根据ID查询status正常的角色 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("id", id).ne("status", SystemCode.STATUS_N.getCode()); + return roleMapper.selectOne(wrapper); + } + + /** + * 接口实现:根据用户ID,查询状态正常的角色列表,其中该用户拥有的角色的checkArr字段为1 + * + * @param userId 用户的ID + * @return 角色列表 + */ + @Override + public List getListByUserId(Integer userId) { + // 查询status正常的角色 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.ne("status", SystemCode.STATUS_N.getCode()); + wrapper.ne("id", 10000); + // 如果userId为0,则表示获取全部角色 + if (userId == 0) { + return roleMapper.selectList(wrapper); + } + // 否则,获取角色后,将该用户已分配的角色checkArr设置为1 + else { + // 获取全部正常角色 + List roleList = roleMapper.selectList(wrapper); + // 获取当前用户拥有的角色ID列表 + List userRoleList = userRoleService.getListByUserId(userId).stream().map(SysUserRole::getRoleId).collect(Collectors.toList()); + // 使用lambda表达式,直接在角色列表上修改checkArr字段 + return roleList.stream().peek( + role -> { + if (userRoleList.contains(role.getId())) { + role.setCheckArr("1"); + role.setLAY_CHECKED(true); + } + } + ).collect(Collectors.toList()); + } + } + + /** + * 接口实现:分页查询接口列表 + * + * @param current 当前页 + * @param size 页大小 + * @param name 检索:名称 + * @param permission 检索:权限字符 + * @return 结果页面 + */ + @Override + public Page getPage(Integer current, Integer size, String name, String permission) { + current = null == current ? 1 : current; + size = null == size ? 10 : size; + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.like(null != name && !"".equals(name), "name", name) + .like(null != permission && !"".equals(permission), "permission", permission); + return roleMapper.selectPage(new Page<>(current, size), wrapper); + } + + /** + * 接口实现:改变角色状态 + * + * @param newStatus 新状态 + * @param roleIds 角色ID列表 + * @return 结果数组 + */ + @Override + public int[] changeStatus(Integer newStatus, Integer[] roleIds) { + if (null == newStatus || null == roleIds) { + throw new ServiceException("新状态或角色ID不能为空"); + } + int[] result = new int[2]; + for (Integer roleId : roleIds) { + SysRole role = new SysRole(); + QueryWrapper wrapper = new QueryWrapper<>(); + role.setId(roleId); + role.setStatus(newStatus); + wrapper.eq("id", roleId) + .ne("status", SystemCode.STATUS_Y_BLOCK.getCode()); + if (roleMapper.update(role, wrapper) > 0) + result[0]++; + else result[1]++; + } + // 清除缓存 + AuthUtils.clearUserMenuListCache(result[0] != 0); + return result; + } + + /** + * 接口实现:通过ID删除角色(注意:已经分配给用户的角色,不允许删除!) + * + * @param roleIds 角色ID + * @return 删除结果:0:成功个数 1:删除失败个数 2:因已分配用户,禁止删除数 + */ + @Override + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) + public int[] deleteRoleById(Integer[] roleIds) { + if (null == roleIds || roleIds.length == 0) { + throw new ServiceException("删除的角色ID不能为空!"); + } + int[] result = new int[3]; + for (int roleId : roleIds) { + // 已经分配用户的角色,不允许删除! + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("role_id", roleId); + if (userRoleService.count(queryWrapper) > 0) { + // throw new ServiceException("当前角色已分配给用户,禁止删除!"); + result[2]++; + } else { + // 删除 用户-角色关联表 中的数据 + QueryWrapper userRoleQueryWrapper = new QueryWrapper<>(); + userRoleQueryWrapper.eq("role_id", roleId); + userRoleService.remove(userRoleQueryWrapper); + // 删除 角色-权限关联表 中的数据 + QueryWrapper roleMenuQueryWrapper = new QueryWrapper<>(); + roleMenuQueryWrapper.eq("role_id", roleId); + roleMenuService.remove(roleMenuQueryWrapper); + // 删除该角色 + if (roleMapper.deleteById(roleId) > 0) { + result[0]++; + } else { + result[1]++; + } + } + } + return result; + } + + /** + * 接口:将指定角色,授权分配给系列用户 + * + * @param roleId 角色ID + * @param userIds 用户ID列表 + * @return 授权结果 + */ + @Override + public boolean authRoleForUsers(Integer roleId, Integer[] userIds) { + // 如果用户列表为空,则直接返回真即可 + if (null == userIds || userIds.length == 0) { + return true; + } + // 存储列表 + List userRoleList = new ArrayList<>(); + for (Integer userId : userIds) { + // 构造数据,并添加至列表 + SysUserRole userRole = new SysUserRole(); + userRole.setRoleId(roleId); + userRole.setUserId(userId); + userRoleList.add(userRole); + } + // 执行插入 + if (userRoleService.saveBatch(userRoleList)) { + // 清除缓存 + AuthUtils.clearUserMenuListCacheById(true, userIds); + return true; + } else + return false; + + } + + /** + * 接口:取消指定角色已授权的系列用户 + * + * @param roleId 角色ID + * @param userIds 用户ID列表 + * @return 取消授权结果 + */ + @Override + public int[] revokeRoleForUsers(Integer roleId, Integer[] userIds) { + if (null == userIds || userIds.length == 0) { + return new int[]{0, 0}; + } + int[] result = new int[2]; + // 遍历用户列表,逐个删除 + for (Integer userId : userIds) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("role_id", roleId).eq("user_id", userId); + // TODO 完善:超级管理员不允许取消授权! + if (userRoleService.remove(wrapper)) { + result[0]++; + } else + result[1]++; + } + // 删除缓存 + AuthUtils.clearUserMenuListCacheById(result[0] != 0, userIds); + return result; + } + + + /** + * 私有方法:将指定角色拥有的菜单/权限,写入角色-菜单关联表 + * + * @param roleId 角色ID + * @param menusIds 菜单ID + */ + private void insertRoleMenu(Integer roleId, Integer[] menusIds) { + List roleMenuList = new ArrayList<>(); + for (Integer menuId : menusIds) { + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + roleMenuList.add(roleMenu); + } + // 如果权限列表不为空 + if (roleMenuList.size() > 0) { + // 批量插入 + roleMenuService.saveBatch(roleMenuList); + } + } + +// /** +// * 私有方法:删除 已缓存的用户列表和权限表 的缓存(详情请见 权限缓存策略) +// * 前提条件:result > 0 & 开启redis +// * +// * @param result 条件:>0 才执行 +// */ +// private void deleteRedisUserMenuCache(int result) { +// if (exciteConfig.getAllowRedis() && result > 0) { +// // 获取已缓存的用户列表 +// Set userSet = (Set) redisService.get("menu:userList"); +// // 统统清空 +// if (userSet != null) { +// for (Integer userId : userSet) { +// redisService.remove("menu:userMenuList:" + userId); +// } +// redisService.remove("menu:userList"); +// } +// } +// } +// +// /** +// * 私有方法:删除指定用户的缓存权限信息 +// * +// * @param result 条件 +// * @param userIds 用户ID +// */ +// private void deleteUserMenuCache(int result, Integer[] userIds) { +// if (result > 0 && exciteConfig.getAllowRedis()) { +// for (int userId : userIds) { +// redisService.remove("menu:userMenuList:" + userId); +// } +// } +// } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysUserRoleServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysUserRoleServiceImpl.java new file mode 100644 index 0000000..6c3836c --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysUserRoleServiceImpl.java @@ -0,0 +1,52 @@ +package com.zxdmy.excite.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zxdmy.excite.system.entity.SysUserRole; +import com.zxdmy.excite.system.mapper.SysUserRoleMapper; +import com.zxdmy.excite.system.service.ISysUserRoleService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

                          + * 系统用户和角色关联表 服务实现类 + *

                          + * + * @author 沈松 + * @since 2021-09-23 + */ +@Service +@AllArgsConstructor +public class SysUserRoleServiceImpl extends ServiceImpl implements ISysUserRoleService { + + SysUserRoleMapper userRoleMapper; + + /** + * 通过角色ID获取用户角色关联列表 + * + * @param roleId 角色ID + * @return 用户角色关联列表 + */ + @Override + public List getListByRoleId(Integer roleId) { + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("role_id", roleId); + return userRoleMapper.selectList(wrapper1); + } + + /** + * 通过用户ID获取用户角色关联列表 + * + * @param userId 用户ID + * @return 用户角色关联列表 + */ + @Override + public List getListByUserId(Integer userId) { + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("user_id", userId); + return userRoleMapper.selectList(wrapper1); + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysUserServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..502361d --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,543 @@ +package com.zxdmy.excite.system.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zxdmy.excite.common.config.ExciteConfig; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.common.enums.SystemCode; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.common.service.RedisService; +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartmentUser; +import com.zxdmy.excite.system.entity.SysRole; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.SysUserRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleFile; +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleUser; +import com.zxdmy.excite.system.entity.cloud.space.CloudFileRole; +import com.zxdmy.excite.system.mapper.SysUserMapper; +import com.zxdmy.excite.system.mapper.cloud.account.CloudDepartmentUserMapper; +import com.zxdmy.excite.system.mapper.cloud.role.CloudRoleFileMapper; +import com.zxdmy.excite.system.service.ISysRoleService; +import com.zxdmy.excite.system.service.ISysUserRoleService; +import com.zxdmy.excite.system.service.ISysUserService; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleService; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleUserService; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileRoleService; +import com.zxdmy.excite.system.utils.AuthUtils; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + *

                          + * 系统用户表 服务实现类 + *

                          + * + * @author 沈松 + * @since 2021-09-01 + */ +@Service +@AllArgsConstructor +public class SysUserServiceImpl extends ServiceImpl implements ISysUserService { + + SysUserMapper userMapper; + + ISysUserRoleService userRoleService; + ICloudFileRoleService iCloudFileRoleService; + ISysRoleService roleService; + + RedisService redisService; + + ExciteConfig exciteConfig; + + CloudDepartmentUserMapper cloudDepartmentUserMapper; + ICloudRoleService iCloudRoleService; + ICloudRoleUserService iCloudRoleUserService; + CloudRoleFileMapper cloudRoleFileMapper; + /** + * 登录服务 + * + * @param username 用户名,邮箱或者手机号 + * @param password 密码 + * @return SysUser:登录成功 | null:登录失败 + */ + @Override + public SysUser login(String username, String password) { + QueryWrapper wrapper = new QueryWrapper<>(); + // 这里用了 Hutool 的验证工具Validator + if (Validator.isMobile(username)) { + wrapper.eq("phone", username).eq("password", password); + } else { + wrapper.eq("login_name", username).eq("password", password); + + } + return userMapper.selectOne(wrapper); + } + + /** + * 获取用户列表 + * + * @param current 当前页 + * @param size 当前页大小 + * @param username 检索用户名 + * @param account 检索邮箱/手机号 + * @return 用户页面信息 + */ + @Override + public Page getPage(Integer current, Integer size, String username, String account) { + size = null == size ? 1 : size; + current = null == current ? 10 : current; + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.like(null != username && !"".equals(username), "username", username).ne("id",10000) + .and(null != account && !"".equals(account), new Consumer>() { + @Override + public void accept(QueryWrapper sysUserQueryWrapper) { + sysUserQueryWrapper + .like("login_name", account) + .or() + .like("phone", account); + } + }); + return userMapper.selectPage(new Page<>(current, size), wrapper); + } + + @Override + public PageList queryByPage(Integer page, Integer limit,String username, String phone, String departmentId) { + Integer pages = limit * (page - 1); + ArrayList list = userMapper.queryByPage(pages, limit,username,phone,departmentId); + Integer count = userMapper.queryByPageCount(username,phone,departmentId); + return new PageList(list,page,limit,count); + } + + /** + * 保存用户:添加 | 更新 + * + * @param user 用户信息 + * @param roleIds 角色ID列表 + * @return 修改的行数 >0:成功 | <=0:失败 + */ + @Override + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) + public int save(SysUser user, Integer[] roleIds) { + // 新添加的用户,邮箱号和手机号,不能重复!只有输入的数据,有手机或邮箱的时候,才核实! + if (StrUtil.isNotEmpty(user.getPhone()) || StrUtil.isNotEmpty(user.getLoginName())) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.ne(null != user.getId(), "id", user.getId()) + .and(wrapper1 -> wrapper1.eq(StrUtil.isNotEmpty(user.getLoginName()), "login_name", user.getLoginName()) + .or(StrUtil.isNotEmpty(user.getPhone())) + .eq(StrUtil.isNotEmpty(user.getPhone()), "phone", user.getPhone()) + ); + if (this.list(wrapper).size() != 0) + throw new ServiceException("输入的账号或者手机号已存在,请修改!"); + } + int result = 0; + // 新建用户:其ID为空 + if (null == user.getId()) { + // 初始化部分信息 + if (null == user.getStatus()) + user.setStatus(SystemCode.STATUS_Y.getCode()); + // 未删除状态 + user.setIsDelete(SystemCode.DELETE_N.getCode()); + // 创建时间 + user.setCreateTime(LocalDateTime.now()); + // 执行新建 + result = userMapper.insert(user); + // 如果当前新用户分配的角色ID不为空 + if (null != roleIds) + // 插入角色 + this.insertUserRole(user.getId(), roleIds); + } + // 更新信息用户:其ID不为空 + else { + user.setUpdateTime(LocalDateTime.now()); + // 先更新用户的基本 + result = userMapper.updateById(user); + + // 本系统中:更新用户信息,不涉及到角色分配! + // 如果也可以在【用户编辑】页面修改用户的权限,则执行如下操作: +// // 先把该用户已有的角色关联信息删除 +// QueryWrapper userRoleQueryWrapper = new QueryWrapper<>(); +// userRoleQueryWrapper.eq("user_id", user.getId()); +// userRoleService.remove(userRoleQueryWrapper); +// // 如果角色为空,表示取消用户的全部权限 +// // 如果当前新用户分配的角色ID不为空,则为该用户修改角色 +// if (null != roleIds && roleIds.length == 0) { +// this.insertUserRole(user.getId(), roleIds); +// } +// // 清除缓存 +// AuthUtils.clearUserMenuListCacheById(result != 0, user.getId()); + + } + return result; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) + public int saveData(SysUser user, Integer[] roleIds,String[] roleIds1,String departmentId) { + // 新添加的用户,邮箱号和手机号,不能重复!只有输入的数据,有手机或邮箱的时候,才核实! + if (StrUtil.isNotEmpty(user.getPhone()) || StrUtil.isNotEmpty(user.getLoginName())) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.ne(null != user.getId(), "id", user.getId()) + .and(wrapper1 -> wrapper1.eq(StrUtil.isNotEmpty(user.getLoginName()), "login_name", user.getLoginName()) + .or(StrUtil.isNotEmpty(user.getPhone())) + .eq(StrUtil.isNotEmpty(user.getPhone()), "phone", user.getPhone()) + ); + if (this.list(wrapper).size() != 0) + throw new ServiceException("输入的账号或者手机号已存在,请修改!"); + } + int result = 0; + // 新建用户:其ID为空 + if (null == user.getId()) { + // 初始化部分信息 + if (null == user.getStatus()) + user.setStatus(SystemCode.STATUS_Y.getCode()); + // 未删除状态 + user.setIsDelete(SystemCode.DELETE_N.getCode()); + // 创建时间 + user.setCreateTime(LocalDateTime.now()); + // 执行新建 + + + + + result = userMapper.insert(user); + + if (null!=departmentId) { + CloudDepartmentUser cloudDepartmentUser = new CloudDepartmentUser(); + cloudDepartmentUser.setUserId(user.getId()); + cloudDepartmentUser.setDepartmentId(Long.valueOf(departmentId)); + cloudDepartmentUserMapper.insert(cloudDepartmentUser); + } + + + // 如果当前新用户分配的角色ID不为空 + if (null != roleIds) + // 插入角色 + this.insertUserRole(user.getId(), roleIds); + this.insertFileRole(user.getId(), roleIds1); + + } + // 更新信息用户:其ID不为空 + else { + user.setUpdateTime(LocalDateTime.now()); + // 先更新用户的基本 + result = userMapper.updateById(user); + + // 本系统中:更新用户信息,不涉及到角色分配! + // 如果也可以在【用户编辑】页面修改用户的权限,则执行如下操作: +// // 先把该用户已有的角色关联信息删除 +// QueryWrapper userRoleQueryWrapper = new QueryWrapper<>(); +// userRoleQueryWrapper.eq("user_id", user.getId()); +// userRoleService.remove(userRoleQueryWrapper); +// // 如果角色为空,表示取消用户的全部权限 +// // 如果当前新用户分配的角色ID不为空,则为该用户修改角色 +// if (null != roleIds && roleIds.length == 0) { +// this.insertUserRole(user.getId(), roleIds); +// } +// // 清除缓存 +// AuthUtils.clearUserMenuListCacheById(result != 0, user.getId()); + + } + return result; + } + /** + * 接口:修改用户状态 + * + * @param newStatus 新状态 + * @param userIds 用户ID列表 + * @return 修改结果数组 0:成功个数 1:失败个数 + */ + @Override + public int[] changeStatus(Integer newStatus, Integer[] userIds) { + /// 信息不能为空 + if (null == newStatus || null == userIds) { + throw new ServiceException("新状态或用户ID不能为空"); + } + // 新状态只能为 0 | 1 + if (newStatus == 0 || newStatus == 1) { + int[] result = new int[2]; + // 遍历用户列表 + for (int userId : userIds) { + // 已登录并且修改的用户ID是当前登录用户,禁止操作(跳过) + if(StpUtil.isLogin() && (StpUtil.getLoginId().toString().equals(String.valueOf(userId)))){ + result[1]++; + }else{ + // 定义用户信息 + SysUser user = new SysUser(); + user.setId(userId); + user.setStatus(newStatus); + // 执行修改(其中锁定,即状态为2的用户禁止修改) + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("id", userId) + .ne("status", SystemCode.STATUS_Y_BLOCK.getCode()); + // 修改成功 + if (userMapper.update(user, wrapper) > 0) { + result[0]++; + // 清除该用户的权限缓存 + AuthUtils.clearUserMenuListCacheById(true, userId); + } else result[1]++; + } + } + // 返回结果 + return result; + } else { + throw new ServiceException("新状态只能为0或1!"); + } + } + + /** + * 接口:给用户分配角色 + * + * @param userId 用户ID + * @param roleIds 角色ID数组 + * @return 修改结果数组 0:分配个数 1:失败个数 + */ + @Override + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) + public boolean setRoleForUser(Integer userId, Integer[] roleIds) { + // 从 用户-角色关联表 中,删除包含该用户的关联信息 + QueryWrapper userRoleQueryWrapper = new QueryWrapper<>(); + userRoleQueryWrapper.eq("user_id", userId); + userRoleService.remove(userRoleQueryWrapper); + // 记录结果 + boolean result; + // 如果角色列表为null,或长度为 0,则表示清除该用户的全部角色,也就没必要插入了 + if (null == roleIds || roleIds.length == 0) { + result = true; + } + // 不为空,执行授权,插入,并返回结果 + else { + result = this.insertUserRole(userId, roleIds); + } + // 清理缓存 + AuthUtils.clearUserMenuListCacheById(result, userId); + return result; + } + @Override + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) + public boolean setCloudRoleForUser(String userId, String[] roleIds) { + // 从 用户-角色关联表 中,删除包含该用户的关联信息 + QueryWrapper userRoleQueryWrapper = new QueryWrapper<>(); + userRoleQueryWrapper.eq("user_id", userId); + iCloudRoleUserService.remove(userRoleQueryWrapper); + // 记录结果 + boolean result; + // 如果角色列表为null,或长度为 0,则表示清除该用户的全部角色,也就没必要插入了 + if (null == roleIds || roleIds.length == 0) { + result = true; + } + // 不为空,执行授权,插入,并返回结果 + else { + result = this.insertUserCloudRole(userId, roleIds); + } + return result; + } + /** + * 接口:根据ID删除用户 + * + * @param userIds 用户ID + * @return 删除结果:>0 表示成功 + */ + @Override + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) + public int[] deleteUserById(Integer[] userIds) { + if (null == userIds || userIds.length == 0) { + throw new SecurityException("用户ID不能为空!"); + } + int[] result = new int[2]; + // 遍历用户 + for (int userId : userIds) { + // TMD 不能删除自己!!! + if (userId != StpUtil.getLoginIdAsInt()) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("id", userId).ne("status", SystemCode.STATUS_Y_BLOCK.getCode()); + // 如果用户删除成功 + if (userMapper.delete(wrapper) > 0) { + // 从 用户-角色关联表 中,删除包含该用户的关联信息 + QueryWrapper userRoleQueryWrapper = new QueryWrapper<>(); + userRoleQueryWrapper.eq("user_id", userId); + userRoleService.remove(userRoleQueryWrapper); + + + + QueryWrapper cloudDepartmentUserQueryWrapper = new QueryWrapper<>(); + cloudDepartmentUserQueryWrapper.eq("user_id", userId); + cloudDepartmentUserMapper.delete(cloudDepartmentUserQueryWrapper); + + + QueryWrapper cloudFileRoleQueryWrapper = new QueryWrapper<>(); + cloudFileRoleQueryWrapper.eq("user_id", userId); + iCloudFileRoleService.remove(cloudFileRoleQueryWrapper); + + + QueryWrapper cloudRoleUserQueryWrapper = new QueryWrapper<>(); + cloudRoleUserQueryWrapper.eq("user_id", userId); + iCloudRoleUserService.remove(cloudRoleUserQueryWrapper); + + // 删除成功结果自增 + result[0]++; + // 清除缓存 + AuthUtils.clearUserMenuListCacheById(true, userId); + } else { + result[1]++; + } + } else { + result[1]++; + } + } + return result; + } + + /** + * 接口:通过角色ID查询用户列表 + * + * @param roleId 角色ID + * @return 用户列表 + */ + @Override + public List getUserListByRoleId(Integer roleId) { + return userMapper.selectUsersByRoleId(roleId); + } + + /** + * 接口:通过角色ID查询不包含此角色的用户列表 + * + * @param roleId 角色ID + * @return 不包含此角色的用户列表 + */ + @Override + public List getUserListByRoleIdNotIn(Integer roleId) { + return userMapper.selectUsersByRoleIdNotIn(roleId); + } + + + + + @Override + public List selectUsersByCloudUploadRoleId(String roleId) { + return userMapper.selectUsersByCloudUploadRoleId(roleId); + } + @Override + public List selectUsersByCloudUploadRoleIdNotIn(String roleId) { + return userMapper.selectUsersByCloudUploadRoleIdNotIn(roleId); + } + /** + * 私有方法:更新用户-角色关联信息 + * + * @param userId 用户ID + * @param roleIds 角色ID数组 + */ + private boolean insertUserRole(Integer userId, Integer[] roleIds) { + // 如果角色列表为空,直接返回真 + if (null == roleIds || roleIds.length == 0) { + return true; + } + // 获取所有状态正常的角色集合 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.ne("status", SystemCode.STATUS_N); + Set roleSet = roleService.list(wrapper).stream().map(SysRole::getId).collect(Collectors.toSet()); + // 存储列表 + List userRoleList = new ArrayList<>(); + for (Integer roleId : roleIds) { + // 只有符合条件的角色,才能添加 + if (roleSet.contains(roleId)) { + SysUserRole userRole = new SysUserRole(); + userRole.setRoleId(roleId); + userRole.setUserId(userId); + userRoleList.add(userRole); + } + } + if (userRoleList.size() > 0) { + return userRoleService.saveBatch(userRoleList); + } else return false; + } + private boolean insertFileRole(Integer userId, String[] roleIds) { + // 如果角色列表为空,直接返回真 + if (null == roleIds || roleIds.length == 0) { + return true; + } + // 获取所有状态正常的角色集合 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.isNull("delete_time"); + Set roleSet = iCloudRoleService.list(wrapper).stream().map(CloudRole::getId).collect(Collectors.toSet()); + // 存储列表 + + List userRoleList = new ArrayList<>(); + for (String roleId : roleIds) { + // 只有符合条件的角色,才能添加 + if (String.valueOf(roleSet).contains(roleId)) { + CloudRoleUser userRole = new CloudRoleUser(); + userRole.setRoleId(Long.valueOf(roleId)); + userRole.setUserId(userId); + userRoleList.add(userRole); + + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("role_id",roleId); + List fileList = cloudRoleFileMapper.selectList(wrapper1); + List fileRoleList = new ArrayList<>(); + for (CloudRoleFile cloudRoleFile:fileList) { + CloudFileRole cloudFileRole = new CloudFileRole(); + cloudFileRole.setFileId(cloudRoleFile.getFileId()); + cloudFileRole.setUserId(userId); + fileRoleList.add(cloudFileRole); + } + iCloudFileRoleService.saveBatch(fileRoleList); + } + } + if (userRoleList.size() > 0) { + return iCloudRoleUserService.saveBatch(userRoleList); + } else return false; + } + + + private boolean insertUserCloudRole(String userId, String[] roleIds) { + // 如果角色列表为空,直接返回真 + if (null == roleIds || roleIds.length == 0) { + return true; + } + // 获取所有状态正常的角色集合 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.isNull("delete_time"); + Set roleSet = iCloudRoleService.list(wrapper).stream().map(CloudRole::getId).collect(Collectors.toSet()); + // 存储列表 + List userRoleList = new ArrayList<>(); + for (String roleId : roleIds) { + // 只有符合条件的角色,才能添加 + if (roleSet.contains(roleId)) { + CloudRoleUser userRole = new CloudRoleUser(); + userRole.setRoleId(Long.valueOf(roleId)); + userRole.setUserId(Integer.valueOf(userId)); + userRoleList.add(userRole); + } + } + if (userRoleList.size() > 0) { + return iCloudRoleUserService.saveBatch(userRoleList); + } else return false; + } + +// /** +// * 删除指定用户的缓存权限信息 +// * +// * @param result 条件:>0 才执行 +// * @param userId 用户ID +// */ +// private void deleteUserMenuCache(int result, int userId) { +// if (result > 0 && exciteConfig.getAllowRedis()) { +// redisService.remove("menu:userMenuList:" + userId); +// } +// } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/account/CloudCompanyServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/account/CloudCompanyServiceImpl.java new file mode 100644 index 0000000..c558bb7 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/account/CloudCompanyServiceImpl.java @@ -0,0 +1,107 @@ +package com.zxdmy.excite.system.service.impl.cloud.account; + +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.system.entity.SysRoleMenu; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.SysUserRole; +import com.zxdmy.excite.system.entity.cloud.account.CloudCompany; +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartment; +import com.zxdmy.excite.system.entity.req.account.ReqCompany; +import com.zxdmy.excite.system.entity.vo.account.CompanyVo; +import com.zxdmy.excite.system.mapper.SysUserMapper; +import com.zxdmy.excite.system.mapper.cloud.account.CloudCompanyMapper; +import com.zxdmy.excite.system.service.cloud.account.ICloudCompanyService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 企业表 服务实现类 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +@Service +@AllArgsConstructor +public class CloudCompanyServiceImpl extends ServiceImpl implements ICloudCompanyService { + private CloudCompanyMapper cloudCompanyMapper; + private SysUserMapper sysUserMapper; + @Override + public PageList queryByPage(Integer page, Integer limit, ReqCompany data) { + Integer pages = limit * (page - 1); + ArrayList list = cloudCompanyMapper.queryByPage(pages, limit,data); + Integer count = cloudCompanyMapper.queryByPageCount(data); + return new PageList(list,page,limit,count); + } + + @Override + public CompanyVo getByData(ReqCompany data) { + return cloudCompanyMapper.getData(data); + } + + @Override + public int saveData(ReqCompany data) { + LocalDateTime localDateTime = LocalDateTime.now(); + CloudCompany saveData = new CloudCompany(); + saveData.setCompanyName(data.getCompanyName()); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + saveData.setCompanySort(0); + saveData.setCreatorId(sysUser.getId()); + saveData.setCreatorName(sysUser.getUsername()); + saveData.setCreateTime(localDateTime); + if(cloudCompanyMapper.insert(saveData)==1){ + return 1; + } + return 0; + } + + @Override + public int updateData(ReqCompany data) { + CloudCompany updateData = new CloudCompany(); + updateData.setId(Long.valueOf(data.getId())); + updateData.setCompanyName(data.getCompanyName()); + if(cloudCompanyMapper.updateById(updateData)==1){ + return 1; + } + return 0; + } + + @Override + public int deleteById(String id) { + if (null == id) { + throw new ServiceException("删除的ID不能为空!"); + } + LocalDateTime localDateTime = LocalDateTime.now(); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + CloudCompany data = cloudCompanyMapper.selectById(id); + if(null!=data){ + data.setDeleteId(sysUser.getId()); + data.setDeleteName(sysUser.getUsername()); + data.setDeleteTime(localDateTime); + return cloudCompanyMapper.updateById(data); + }else{ + return 0; + } + } + + @Override + public List queryByData() { + return cloudCompanyMapper.queryByData(); + } + + @Override + public List getList() { + return cloudCompanyMapper.getList(); + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/account/CloudDepartmentServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/account/CloudDepartmentServiceImpl.java new file mode 100644 index 0000000..d472946 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/account/CloudDepartmentServiceImpl.java @@ -0,0 +1,245 @@ +package com.zxdmy.excite.system.service.impl.cloud.account; + +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartmentUser; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.cloud.account.CloudCompany; +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartment; +import com.zxdmy.excite.system.entity.dto.DepartmentUserTreeNode; +import com.zxdmy.excite.system.entity.req.account.ReqDepartment; +import com.zxdmy.excite.system.entity.vo.account.DepartmentVo; +import com.zxdmy.excite.system.mapper.SysUserMapper; +import com.zxdmy.excite.system.mapper.cloud.account.CloudCompanyMapper; +import com.zxdmy.excite.system.mapper.cloud.account.CloudDepartmentMapper; +import com.zxdmy.excite.system.mapper.cloud.account.CloudDepartmentUserMapper; +import com.zxdmy.excite.system.service.cloud.account.ICloudDepartmentService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import javax.xml.transform.Result; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + *

                          + * 部门表 服务实现类 + *

                          + * + * @author ss + * @since 2026-01-24 + */ +@Service +@AllArgsConstructor +public class CloudDepartmentServiceImpl extends ServiceImpl implements ICloudDepartmentService { + + private CloudDepartmentMapper cloudDepartmentMapper; + private CloudCompanyMapper cloudCompanyMapper; + private SysUserMapper sysUserMapper; + private CloudDepartmentUserMapper cloudDepartmentUserMapper; + @Override + public PageList queryByPage(Integer page, Integer limit, ReqDepartment data) { + Integer pages = limit * (page - 1); + ArrayList list = cloudDepartmentMapper.queryByPage(pages, limit,data); + Integer count = cloudDepartmentMapper.queryByPageCount(data); + return new PageList(list,page,limit,count); + } + + @Override + public DepartmentVo getByData(ReqDepartment data) { + return cloudDepartmentMapper.getData(data); + } + + @Override + public int saveData(ReqDepartment data) { + LocalDateTime localDateTime = LocalDateTime.now(); + CloudDepartment saveData = new CloudDepartment(); + + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("id",data.getId()); + Integer company = cloudCompanyMapper.selectCount(wrapper); + if(company>0){ + saveData.setDepartmentParentId(Long.valueOf("0")); + saveData.setCompanyId(Long.valueOf(data.getId())); + }else{ + saveData.setDepartmentParentId(Long.valueOf(data.getId())); + saveData.setCompanyId(Long.valueOf(data.getCompanyId())); + } + saveData.setDepartmentName(data.getDepartmentName()); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + saveData.setDepartmentSort(0); + saveData.setCreatorId(sysUser.getId()); + saveData.setCreatorName(sysUser.getUsername()); + saveData.setCreateTime(localDateTime); + if(cloudDepartmentMapper.insert(saveData)==1){ + return 1; + } + return 0; + } + + @Override + public int updateData(ReqDepartment data) { + CloudDepartment updateData = new CloudDepartment(); + updateData.setId(Long.valueOf(data.getId())); + updateData.setDepartmentName(data.getDepartmentName()); + if(cloudDepartmentMapper.updateById(updateData)==1){ + return 1; + } + return 0; + } + + @Override + public int deleteById(String id) { + if (null == id) { + throw new ServiceException("删除的ID不能为空!"); + } + LocalDateTime localDateTime = LocalDateTime.now(); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + CloudDepartment data = cloudDepartmentMapper.selectById(id); + if(null!=data){ + data.setDeleteId(sysUser.getId()); + data.setDeleteName(sysUser.getUsername()); + data.setDeleteTime(localDateTime); + return cloudDepartmentMapper.updateById(data); + }else{ + return 0; + } + } + + @Override + public int changeDepartment(String userId, String departmentId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("user_id",userId); + List list = cloudDepartmentUserMapper.selectList(queryWrapper); + if (list.size()>0) { + CloudDepartmentUser cloudDepartmentUser = cloudDepartmentUserMapper.selectById(list.get(0).getId()); + cloudDepartmentUser.setDepartmentId(Long.valueOf(departmentId)); + return cloudDepartmentUserMapper.updateById(cloudDepartmentUser); + } + return 0; + } + @Override + public List getList(Long id) { + return cloudDepartmentMapper.getList(id); + } + + + public List buildDepartmentUserTree(Long companyId) { + // 1. 查询所有部门 + List departments = cloudDepartmentMapper.selectByCompanyId(companyId); + + // 2. 查询所有部门-用户关系 + List departmentUsers = cloudDepartmentUserMapper.selectByCompanyId(companyId); + + // 3. 按部门分组用户关系 + Map> deptUserMap = departmentUsers.stream() + .collect(Collectors.groupingBy(CloudDepartmentUser::getDepartmentId)); + + // 4. 查询所有用户信息 + List userIds = departmentUsers.stream() + .map(CloudDepartmentUser::getUserId) + .distinct() + .collect(Collectors.toList()); + + Map userMap = new HashMap<>(); + if (!userIds.isEmpty()) { + List users = sysUserMapper.selectByIds(userIds); + users.forEach(user -> userMap.put(user.getId(), user)); + } + + // 5. 构建部门树节点映射 + Map deptNodeMap = new HashMap<>(); + for (CloudDepartment dept : departments) { + DepartmentUserTreeNode node = new DepartmentUserTreeNode(dept); + deptNodeMap.put(dept.getId(), node); + } + + // 6. 将用户添加到部门节点 + for (Map.Entry> entry : deptUserMap.entrySet()) { + Long deptId = entry.getKey(); + DepartmentUserTreeNode deptNode = deptNodeMap.get(deptId); + if (deptNode != null) { + for (CloudDepartmentUser du : entry.getValue()) { + SysUser user = userMap.get(du.getUserId()); + if (user != null) { + DepartmentUserTreeNode userNode = new DepartmentUserTreeNode(user, deptId); + deptNode.getChildren().add(userNode); + } + } + } + } + + // 7. 构建树形结构 + List tree = new ArrayList<>(); + for (DepartmentUserTreeNode node : deptNodeMap.values()) { + if (node.getParentId() == 0) { + // 根节点 + tree.add(node); + buildTreeRecursive(node, deptNodeMap); + } + } + + // 8. 排序 + sortTreeNodes(tree); + + return tree; + } + + private void buildTreeRecursive(DepartmentUserTreeNode parentNode, + Map deptNodeMap) { + // 添加子部门 + List children = new ArrayList<>(); + for (DepartmentUserTreeNode node : deptNodeMap.values()) { + if (node.getType().equals("department") && + parentNode.getId().equals(node.getParentId())) { + children.add(node); + buildTreeRecursive(node, deptNodeMap); + } + } + + // 合并已有的用户节点 + if (!parentNode.getChildren().isEmpty()) { + // 只保留用户节点,部门节点在children中添加 + List userNodes = parentNode.getChildren().stream() + .filter(n -> n.getType().equals("user")) + .collect(Collectors.toList()); + children.addAll(userNodes); + } + + parentNode.setChildren(children); + } + + /** + * 排序:部门按sort排序,用户按name排序 + */ + private void sortTreeNodes(List nodes) { + if (nodes == null || nodes.isEmpty()) { + return; + } + + nodes.sort((n1, n2) -> { + if (n1.getType().equals("department") && n2.getType().equals("department")) { + return Integer.compare(n1.getSort(), n2.getSort()); + } else if (n1.getType().equals("user") && n2.getType().equals("user")) { + return n1.getTitle().compareTo(n2.getTitle()); + } else { + // 部门在前,用户在后 + return n1.getType().equals("department") ? -1 : 1; + } + }); + + for (DepartmentUserTreeNode node : nodes) { + if (node.getType().equals("department") && !node.getChildren().isEmpty()) { + sortTreeNodes(node.getChildren()); + } + } + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/account/CloudDepartmentUserServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/account/CloudDepartmentUserServiceImpl.java new file mode 100644 index 0000000..d53a569 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/account/CloudDepartmentUserServiceImpl.java @@ -0,0 +1,20 @@ +package com.zxdmy.excite.system.service.impl.cloud.account; + +import com.zxdmy.excite.system.entity.cloud.account.CloudDepartmentUser; +import com.zxdmy.excite.system.mapper.cloud.account.CloudDepartmentUserMapper; +import com.zxdmy.excite.system.service.cloud.account.ICloudDepartmentUserService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

                          + * 部门用户ID 服务实现类 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +@Service +public class CloudDepartmentUserServiceImpl extends ServiceImpl implements ICloudDepartmentUserService { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/collection/CloudUserCollectionServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/collection/CloudUserCollectionServiceImpl.java new file mode 100644 index 0000000..0e17403 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/collection/CloudUserCollectionServiceImpl.java @@ -0,0 +1,82 @@ +package com.zxdmy.excite.system.service.impl.cloud.collection; + +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.cloud.account.CloudCompany; +import com.zxdmy.excite.system.entity.cloud.collection.CloudUserCollection; +import com.zxdmy.excite.system.entity.req.account.ReqCompany; +import com.zxdmy.excite.system.entity.req.collection.ReqCloudUserCollection; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.vo.account.CompanyVo; +import com.zxdmy.excite.system.entity.vo.collection.CloudUserCollectionVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.mapper.SysUserMapper; +import com.zxdmy.excite.system.mapper.cloud.collection.CloudUserCollectionMapper; +import com.zxdmy.excite.system.service.cloud.collection.ICloudUserCollectionService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 收藏表 服务实现类 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Service +@AllArgsConstructor +public class CloudUserCollectionServiceImpl extends ServiceImpl implements ICloudUserCollectionService { + CloudUserCollectionMapper cloudUserCollectionMapper; + SysUserMapper sysUserMapper; + @Override + public PageList queryByPage(Integer page, Integer limit, ReqCloudUserCollection data) { + Integer pages = limit * (page - 1); + ArrayList list = cloudUserCollectionMapper.queryByPage(pages, limit,data); + Integer count = cloudUserCollectionMapper.queryByPageCount(data); + return new PageList(list,page,limit,count); + } + + @Override + public CloudUserCollectionVo getByData(ReqCloudUserCollection data) { + return cloudUserCollectionMapper.getData(data); + } + + @Override + public int saveData(ReqCloudUserCollection data) { + LocalDateTime localDateTime = LocalDateTime.now(); + CloudUserCollection saveData = new CloudUserCollection(); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + saveData.setFileId(Long.valueOf(data.getFileId())); + saveData.setUserId(sysUser.getId()); + saveData.setCreateTime(localDateTime); + if(cloudUserCollectionMapper.insert(saveData)==1){ + return 1; + } + return 0; + } + + + @Override + public int deleteById(String id) { + if (null == id) { + throw new ServiceException("删除的ID不能为空!"); + } + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("file_id",id); + wrapper.eq("user_id",StpUtil.getLoginIdAsInt()); + List list = cloudUserCollectionMapper.selectList(wrapper); + if(list.size()>0){ + return cloudUserCollectionMapper.deleteById(list.get(0).getId()); + } + return 0; + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/lately/CloudUserLatelyServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/lately/CloudUserLatelyServiceImpl.java new file mode 100644 index 0000000..ca8f4b4 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/lately/CloudUserLatelyServiceImpl.java @@ -0,0 +1,97 @@ +package com.zxdmy.excite.system.service.impl.cloud.lately; + +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.cloud.collection.CloudUserCollection; +import com.zxdmy.excite.system.entity.cloud.lately.CloudUserLately; +import com.zxdmy.excite.system.entity.cloud.space.CloudFile; +import com.zxdmy.excite.system.entity.req.collection.ReqCloudUserCollection; +import com.zxdmy.excite.system.entity.req.lately.ReqCloudUserLately; +import com.zxdmy.excite.system.entity.req.trace.ReqCloudFileTrace; +import com.zxdmy.excite.system.entity.vo.collection.CloudUserCollectionVo; +import com.zxdmy.excite.system.entity.vo.lately.CloudUserLatelyVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.mapper.SysUserMapper; +import com.zxdmy.excite.system.mapper.cloud.lately.CloudUserLatelyMapper; +import com.zxdmy.excite.system.mapper.cloud.space.CloudFileMapper; +import com.zxdmy.excite.system.service.cloud.lately.ICloudUserLatelyService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zxdmy.excite.system.service.cloud.trace.ICloudFileTraceService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 最近文件表 服务实现类 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Service +@AllArgsConstructor +public class CloudUserLatelyServiceImpl extends ServiceImpl implements ICloudUserLatelyService { + CloudUserLatelyMapper cloudUserLatelyMapper; + SysUserMapper sysUserMapper; + CloudFileMapper cloudFileMapper; + ICloudFileTraceService iCloudFileTraceService; + @Override + public PageList queryByPage(Integer page, Integer limit, ReqCloudUserLately data) { + Integer pages = limit * (page - 1); + ArrayList list = cloudUserLatelyMapper.queryByPage(pages, limit,data); + Integer count = cloudUserLatelyMapper.queryByPageCount(data); + return new PageList(list,page,limit,count); + } + + @Override + public CloudUserLatelyVo getByData(ReqCloudUserLately data) { + return cloudUserLatelyMapper.getData(data); + } + + @Override + public int saveData(ReqCloudUserLately data) { + LocalDateTime localDateTime = LocalDateTime.now(); + CloudUserLately saveData = new CloudUserLately(); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + saveData.setFileId(Long.valueOf(data.getFileId())); + saveData.setUserId(sysUser.getId()); + saveData.setCreateTime(localDateTime); + saveData.setLatelyTime(localDateTime); + if(cloudUserLatelyMapper.insert(saveData)==1){ + + CloudFile cloudFile = cloudFileMapper.selectById(data.getFileId()); + + ReqCloudFileTrace reqCloudFileTrace = new ReqCloudFileTrace(); + reqCloudFileTrace.setFileId(data.getFileId()); + reqCloudFileTrace.setTraceName("查看了 "+cloudFile.getFileName()+" 文件"); + iCloudFileTraceService.saveData(reqCloudFileTrace); + + + return 1; + } + return 0; + } + + + @Override + public int deleteById(String id) { + if (null == id) { + throw new ServiceException("删除的ID不能为空!"); + } + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("file_id",id); + wrapper.eq("user_id",StpUtil.getLoginIdAsInt()); + List list = cloudUserLatelyMapper.selectList(wrapper); + if(list.size()>0){ + return cloudUserLatelyMapper.deleteById(list.get(0).getId()); + } + return 0; + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/role/CloudRoleFileServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/role/CloudRoleFileServiceImpl.java new file mode 100644 index 0000000..1093ea5 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/role/CloudRoleFileServiceImpl.java @@ -0,0 +1,20 @@ +package com.zxdmy.excite.system.service.impl.cloud.role; + +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleFile; +import com.zxdmy.excite.system.mapper.cloud.role.CloudRoleFileMapper; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleFileService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

                          + * 云盘权限文件表 服务实现类 + *

                          + * + * @author 沈松 + * @since 2026-02-01 + */ +@Service +public class CloudRoleFileServiceImpl extends ServiceImpl implements ICloudRoleFileService { + +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/role/CloudRoleServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/role/CloudRoleServiceImpl.java new file mode 100644 index 0000000..dab35aa --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/role/CloudRoleServiceImpl.java @@ -0,0 +1,300 @@ +package com.zxdmy.excite.system.service.impl.cloud.role; + +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.common.enums.SystemCode; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.system.entity.SysRole; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.SysUserRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleFile; +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleUser; +import com.zxdmy.excite.system.entity.cloud.space.CloudFileRole; +import com.zxdmy.excite.system.entity.req.role.ReqRole; +import com.zxdmy.excite.system.entity.vo.role.RoleVo; +import com.zxdmy.excite.system.mapper.SysUserMapper; +import com.zxdmy.excite.system.mapper.cloud.role.CloudRoleFileMapper; +import com.zxdmy.excite.system.mapper.cloud.role.CloudRoleMapper; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleUserService; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileRoleService; +import com.zxdmy.excite.system.utils.AuthUtils; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

                          + * 云盘权限表 服务实现类 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +@Service +@AllArgsConstructor +public class CloudRoleServiceImpl extends ServiceImpl implements ICloudRoleService { + private CloudRoleMapper cloudRoleMapper; + private SysUserMapper sysUserMapper; + private ICloudRoleUserService iCloudRoleUserService; + private CloudRoleFileMapper cloudRoleFileMapper; + private ICloudFileRoleService iCloudFileRoleService; + + @Override + public PageList queryByPage(Integer page, Integer limit, ReqRole data) { + Integer pages = limit * (page - 1); + ArrayList list = cloudRoleMapper.queryByPage(pages, limit,data); + Integer count = cloudRoleMapper.queryByPageCount(data); + return new PageList(list,page,limit,count); + } + + @Override + public RoleVo getByData(ReqRole data) { + return cloudRoleMapper.getData(data); + } + + @Override + public int saveData(ReqRole data) { + LocalDateTime localDateTime = LocalDateTime.now(); + CloudRole saveData = new CloudRole(); + saveData.setRoleName(data.getRoleName()); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + saveData.setRoleDown(data.getRoleDown()); + saveData.setRoleUpload(data.getRoleUpload()); + saveData.setCreatorId(sysUser.getId()); + saveData.setCreatorName(sysUser.getUsername()); + saveData.setCreateTime(localDateTime); + if(cloudRoleMapper.insert(saveData)==1){ + + for (String fileId:data.getIds()) { + CloudRoleFile cloudRoleFile = new CloudRoleFile(); + cloudRoleFile.setFileId(Long.valueOf(fileId)); + cloudRoleFile.setRoleId(saveData.getId()); + cloudRoleFileMapper.insert(cloudRoleFile); + } + + return 1; + } + return 0; + } + + @Override + public int updateData(ReqRole data) { + CloudRole updateData = new CloudRole(); + updateData.setId(Long.valueOf(data.getId())); + updateData.setRoleName(data.getRoleName()); + updateData.setRoleDown(data.getRoleDown()); + updateData.setRoleUpload(data.getRoleUpload()); + if(cloudRoleMapper.updateById(updateData)==1){ + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("role_id",updateData.getId()); + List list = cloudRoleFileMapper.selectList(wrapper); + for (CloudRoleFile cloudRoleFile:list) { + cloudRoleFileMapper.deleteById(cloudRoleFile.getId()); + } + + + for (String fileId:data.getIds()) { + CloudRoleFile cloudRoleFile = new CloudRoleFile(); + cloudRoleFile.setFileId(Long.valueOf(fileId)); + cloudRoleFile.setRoleId(updateData.getId()); + cloudRoleFileMapper.insert(cloudRoleFile); + } + + + return 1; + } + return 0; + } + + @Override + public int deleteById(String id) { + if (null == id) { + throw new ServiceException("删除的ID不能为空!"); + } + LocalDateTime localDateTime = LocalDateTime.now(); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + CloudRole data = cloudRoleMapper.selectById(id); + if(null!=data){ + data.setDeleteId(sysUser.getId()); + data.setDeleteName(sysUser.getUsername()); + data.setDeleteTime(localDateTime); + return cloudRoleMapper.updateById(data); + }else{ + return 0; + } + } + + @Override + public List queryByData() { + return cloudRoleMapper.queryByData(); + } + + + @Override + public int[] changeUploadStatus(Integer newStatus, String[] ids) { + /// 信息不能为空 + if (null == newStatus || null == ids) { + throw new ServiceException("新状态或ID不能为空"); + } + // 新状态只能为 0 | 1 + if (newStatus == 0 || newStatus == 1) { + int[] result = new int[2]; + for (String id : ids) { + CloudRole data = cloudRoleMapper.selectById(id); + data.setRoleUpload(newStatus); + if (cloudRoleMapper.updateById(data) > 0) { + result[0]++; + } else result[1]++; + } + // 返回结果 + return result; + } else { + throw new ServiceException("新状态只能为0或1!"); + } + } + @Override + public int[] changeDownStatus(Integer newStatus, String[] ids) { + /// 信息不能为空 + if (null == newStatus || null == ids) { + throw new ServiceException("新状态或ID不能为空"); + } + // 新状态只能为 0 | 1 + if (newStatus == 0 || newStatus == 1) { + int[] result = new int[2]; + for (String id : ids) { + CloudRole data = cloudRoleMapper.selectById(id); + data.setRoleDown(newStatus); + if (cloudRoleMapper.updateById(data) > 0) { + result[0]++; + } else result[1]++; + } + // 返回结果 + return result; + } else { + throw new ServiceException("新状态只能为0或1!"); + } + } + @Override + public int[] changeDeleteStatus(Integer newStatus, String[] ids) { + /// 信息不能为空 + if (null == newStatus || null == ids) { + throw new ServiceException("新状态或ID不能为空"); + } + // 新状态只能为 0 | 1 + if (newStatus == 0 || newStatus == 1) { + int[] result = new int[2]; + for (String id : ids) { + CloudRole data = cloudRoleMapper.selectById(id); + data.setRoleDelete(newStatus); + if (cloudRoleMapper.updateById(data) > 0) { + result[0]++; + } else result[1]++; + } + // 返回结果 + return result; + } else { + throw new ServiceException("新状态只能为0或1!"); + } + } + @Override + public boolean authRoleForUsers(String roleId, String[] userIds) { + // 如果用户列表为空,则直接返回真即可 + if (null == userIds || userIds.length == 0) { + return true; + } + // 存储列表 + List userRoleList = new ArrayList<>(); + for (String userId : userIds) { + // 构造数据,并添加至列表 + CloudRoleUser userRole = new CloudRoleUser(); + userRole.setRoleId(Long.valueOf(roleId)); + userRole.setUserId(Integer.valueOf(userId)); + userRoleList.add(userRole); + + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("role_id",roleId); + List fileList = cloudRoleFileMapper.selectList(wrapper1); + List fileRoleList = new ArrayList<>(); + for (CloudRoleFile cloudRoleFile:fileList) { + CloudFileRole cloudFileRole = new CloudFileRole(); + cloudFileRole.setFileId(cloudRoleFile.getFileId()); + cloudFileRole.setUserId(Integer.valueOf(userId)); + fileRoleList.add(cloudFileRole); + } + iCloudFileRoleService.saveBatch(fileRoleList); + } + // 执行插入 + if (iCloudRoleUserService.saveBatch(userRoleList)) { + return true; + } else + return false; + + } + + @Override + public int[] revokeRoleForUsers(String roleId, String[] userIds) { + if (null == userIds || userIds.length == 0) { + return new int[]{0, 0}; + } + int[] result = new int[2]; + // 遍历用户列表,逐个删除 + for (String userId : userIds) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("role_id", roleId).eq("user_id", userId); + // TODO 完善:超级管理员不允许取消授权! + if (iCloudRoleUserService.remove(wrapper)) { + + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("role_id",roleId); + List fileList = cloudRoleFileMapper.selectList(wrapper1); + for (CloudRoleFile cloudRoleFile:fileList) { + + QueryWrapper wrapper2 = new QueryWrapper<>(); + wrapper2.eq("file_id", cloudRoleFile.getFileId()); + wrapper2.eq("user_id", userId); + iCloudFileRoleService.remove(wrapper2); + } + + result[0]++; + } else + result[1]++; + } + return result; + } + + @Override + public List getListByUserId(Integer userId) { + // 查询status正常的角色 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.isNull("delete_time"); + // 如果userId为0,则表示获取全部角色 + if (userId == 0) { + return cloudRoleMapper.selectList(wrapper); + } + // 否则,获取角色后,将该用户已分配的角色checkArr设置为1 + else { + // 获取全部正常角色 + List roleList = cloudRoleMapper.selectList(wrapper); + // 获取当前用户拥有的角色ID列表 + List userRoleList = iCloudRoleUserService.getListByUserId(userId).stream().map(CloudRoleUser::getRoleId).collect(Collectors.toList()); + // 使用lambda表达式,直接在角色列表上修改checkArr字段 + return roleList.stream().peek( + role -> { + if (userRoleList.contains(role.getId())) { + role.setCheckArr("1"); + role.setLAY_CHECKED(true); + } + } + ).collect(Collectors.toList()); + } + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/role/CloudRoleUserServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/role/CloudRoleUserServiceImpl.java new file mode 100644 index 0000000..965a8fd --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/role/CloudRoleUserServiceImpl.java @@ -0,0 +1,63 @@ +package com.zxdmy.excite.system.service.impl.cloud.role; + +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zxdmy.excite.system.entity.SysUserRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.entity.cloud.role.CloudRoleUser; +import com.zxdmy.excite.system.mapper.cloud.role.CloudRoleMapper; +import com.zxdmy.excite.system.mapper.cloud.role.CloudRoleUserMapper; +import com.zxdmy.excite.system.service.ISysUserRoleService; +import com.zxdmy.excite.system.service.cloud.role.ICloudRoleUserService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zxdmy.excite.system.utils.AuthUtils; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 云盘权限用户表 服务实现类 + *

                          + * + * @author ss + * @since 2026-01-27 + */ +@Service +@AllArgsConstructor +public class CloudRoleUserServiceImpl extends ServiceImpl implements ICloudRoleUserService { + CloudRoleUserMapper cloudRoleUserMapper; + CloudRoleMapper cloudRoleMapper; + @Override + public List getListByUserId(Integer userId) { + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.eq("user_id", userId); + return cloudRoleUserMapper.selectList(wrapper1); + } + + @Override + public CloudRole getCloudShareRole(Integer id) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("user_id",id); + List roleList = cloudRoleUserMapper.selectList(wrapper); + CloudRole data = new CloudRole(); + data.setRoleUpload(0); + data.setRoleDown(0); + data.setRoleDelete(0); + for (CloudRoleUser cloudRoleUser:roleList) { + CloudRole cloudRole = cloudRoleMapper.selectById(cloudRoleUser.getRoleId()); + if(null!=cloudRole.getRoleUpload() && cloudRole.getRoleUpload()==1){ + data.setRoleUpload(1); + } + if(null!=cloudRole.getRoleDown() && cloudRole.getRoleDown()==1){ + data.setRoleDown(1); + } + if(null!=cloudRole.getRoleDelete() && cloudRole.getRoleDelete()==1){ + data.setRoleDelete(1); + } + } + return data; + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/space/CloudFileRoleServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/space/CloudFileRoleServiceImpl.java new file mode 100644 index 0000000..fed16a5 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/space/CloudFileRoleServiceImpl.java @@ -0,0 +1,60 @@ +package com.zxdmy.excite.system.service.impl.cloud.space; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.cloud.space.CloudFileRole; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFileRole; +import com.zxdmy.excite.system.entity.vo.space.CloudFileRoleVo; +import com.zxdmy.excite.system.entity.vo.space.CloudRoleFileVo; +import com.zxdmy.excite.system.mapper.cloud.space.CloudFileRoleMapper; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileRoleService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

                          + * 文件用户权限表 服务实现类 + *

                          + * + * @author 沈松 + * @since 2026-01-30 + */ +@Service +@AllArgsConstructor +public class CloudFileRoleServiceImpl extends ServiceImpl implements ICloudFileRoleService { + CloudFileRoleMapper cloudFileRoleMapper; + @Override + public List getFileRole(String id) { + return cloudFileRoleMapper.getFileRole(id); + } + @Override + public List getRoleFile(String id) { + return cloudFileRoleMapper.getRoleFile(id); + } + @Override + public List getRoleFileCheck(String id) { + return cloudFileRoleMapper.getRoleFileCheck(id); + } + @Override + public CloudFileRole getData(ReqCloudFileRole data) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("user_id",data.getUserId()); + wrapper.eq("file_id",data.getFileId()); + List cloudFileRole = cloudFileRoleMapper.selectList(wrapper); + if(cloudFileRole.size()>0){ + return cloudFileRole.get(0); + } + return null; + } + + @Override + public List getFileRoleByUseId(Integer id) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("user_id",id); + List cloudFileRole = cloudFileRoleMapper.selectList(wrapper); + return cloudFileRole; + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/space/CloudFileServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/space/CloudFileServiceImpl.java new file mode 100644 index 0000000..48b5200 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/space/CloudFileServiceImpl.java @@ -0,0 +1,290 @@ +package com.zxdmy.excite.system.service.impl.cloud.space; + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.common.enums.CloudCode; +import com.zxdmy.excite.common.enums.SystemCode; +import com.zxdmy.excite.common.exception.ServiceException; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.cloud.role.CloudRole; +import com.zxdmy.excite.system.entity.cloud.space.CloudFile; +import com.zxdmy.excite.system.entity.cloud.space.CloudFileRole; +import com.zxdmy.excite.system.entity.req.space.ReqCloudFile; +import com.zxdmy.excite.system.entity.req.trace.ReqCloudFileTrace; +import com.zxdmy.excite.system.entity.vo.space.CloudFileRoleVo; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.mapper.SysUserMapper; +import com.zxdmy.excite.system.mapper.cloud.space.CloudFileMapper; +import com.zxdmy.excite.system.mapper.cloud.space.CloudFileRoleMapper; +import com.zxdmy.excite.system.service.cloud.space.ICloudFileService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zxdmy.excite.system.service.cloud.trace.ICloudFileTraceService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + *

                          + * 文件表 服务实现类 + *

                          + * + * @author ss + * @since 2026-01-28 + */ +@Service +@AllArgsConstructor +public class CloudFileServiceImpl extends ServiceImpl implements ICloudFileService { + + private CloudFileMapper cloudFileMapper; + private SysUserMapper sysUserMapper; + private CloudFileRoleMapper cloudFileRoleMapper; + private ICloudFileTraceService iCloudFileTraceService; + + @Override + public PageList queryByPage(Integer page, Integer limit, ReqCloudFile data) { + Integer pages = limit * (page - 1); + ArrayList list = cloudFileMapper.queryByPage(pages, limit,data); + Integer count = cloudFileMapper.queryByPageCount(data); + return new PageList(list,page,limit,count); + } + + + @Override + public PageList queryByRecyclePage(Integer page, Integer limit, ReqCloudFile data) { + Integer pages = limit * (page - 1); + ArrayList list = cloudFileMapper.queryByRecyclePage(pages, limit,data); + Integer count = cloudFileMapper.queryByRecyclePageCount(data); + return new PageList(list,page,limit,count); + } + @Override + public CloudFileVo getByData(ReqCloudFile data) { + return cloudFileMapper.getData(data); + } + + @Override + public int saveData(ReqCloudFile data) { + LocalDateTime localDateTime = LocalDateTime.now(); + CloudFile saveData = new CloudFile(); + saveData.setFileName(data.getFileName()); + saveData.setFileFormat(CloudCode.FOLDER_NAME.getCode()); + saveData.setFileFolder(Integer.valueOf(SystemCode.FOLDER_Y.getCode())); + saveData.setFileImage(CloudCode.FOLDER_IMAGE.getCode()); + saveData.setFileSort(0); + + if(data.getFileParentId().equals("0")){ + saveData.setFileTopId(Long.valueOf("0")); + saveData.setFileParentId(Long.valueOf("0")); + }else{ + saveData.setFileTopId(Long.valueOf(data.getFileParentId())); + saveData.setFileParentId(Long.valueOf(data.getFileParentId())); + } + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + saveData.setCreatorId(sysUser.getId()); + saveData.setCreatorName(sysUser.getUsername()); + saveData.setCreateTime(localDateTime); + if(cloudFileMapper.insert(saveData)==1){ + for (Integer userId:data.getIds()) { + CloudFileRole cloudFileRole = new CloudFileRole(); + cloudFileRole.setFileId(saveData.getId()); + cloudFileRole.setUserId(userId); + cloudFileRoleMapper.insert(cloudFileRole); + } + return 1; + } + return 0; + } + + + @Override + public int saveFileData(ReqCloudFile data) { + LocalDateTime localDateTime = LocalDateTime.now(); + CloudFile saveData = new CloudFile(); + String[] file = data.getFileName().split("\\."); + String fileName = null; + String format = null; + if(file.length>0) { + fileName = file[0].toString(); + format = file[1].toString(); + saveData.setFileName(fileName); + saveData.setFileFormat(format); + + } + saveData.setFileTop(0); + saveData.setFileName(fileName); + saveData.setFileFormat(format); + saveData.setFileFolder(Integer.valueOf(SystemCode.FOLDER_N.getCode())); + saveData.setFileImage(CloudCode.PDF_IMAGE.getCode()); + saveData.setFileSort(0); + saveData.setFileSize(data.getFileSize()); + saveData.setFileOss(data.getFileOss()); + if(data.getFileParentId().equals("0")){ + saveData.setFileTopId(Long.valueOf("0")); + saveData.setFileParentId(Long.valueOf("0")); + }else{ + saveData.setFileTopId(Long.valueOf(data.getFileParentId())); + saveData.setFileParentId(Long.valueOf(data.getFileParentId())); + } + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + saveData.setCreatorId(sysUser.getId()); + saveData.setCreatorName(sysUser.getUsername()); + saveData.setCreateTime(localDateTime); + if(cloudFileMapper.insert(saveData)==1){ + + + ReqCloudFileTrace reqCloudFileTrace = new ReqCloudFileTrace(); + reqCloudFileTrace.setFileId(saveData.getId().toString()); + reqCloudFileTrace.setTraceName("上传了 "+fileName+" 文件"); + iCloudFileTraceService.saveData(reqCloudFileTrace); + + + return 1; + } + return 0; + } + + @Override + public int updateFileData(ReqCloudFile data) { + LocalDateTime localDateTime = LocalDateTime.now(); + CloudFile saveData = cloudFileMapper.selectById(data.getId()); + saveData.setFileOss(data.getFileOss()); + saveData.setFileSize(data.getFileSize()); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + saveData.setUpdaterId(sysUser.getId()); + saveData.setUpdaterName(sysUser.getUsername()); + saveData.setUpdateTime(localDateTime); + if(cloudFileMapper.updateById(saveData)==1){ + + ReqCloudFileTrace reqCloudFileTrace = new ReqCloudFileTrace(); + reqCloudFileTrace.setFileId(saveData.getId().toString()); + reqCloudFileTrace.setTraceName("替换了 "+saveData.getFileName()+" 文件"); + iCloudFileTraceService.saveData(reqCloudFileTrace); + + return 1; + } + return 0; + } + + + @Override + public int updateData(ReqCloudFile data) { + LocalDateTime localDateTime = LocalDateTime.now(); + + CloudFile updateData = new CloudFile(); + updateData.setId(Long.valueOf(data.getId())); + updateData.setFileName(data.getFileName()); + + + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + updateData.setUpdateTime(localDateTime); + updateData.setUpdaterId(sysUser.getId()); + updateData.setUpdaterName(sysUser.getUsername()); + if(cloudFileMapper.updateById(updateData)==1){ + + List roleList = cloudFileRoleMapper.getFileRole(data.getId()); + for (CloudFileRoleVo cloudFileRoleVo:roleList) { + cloudFileRoleMapper.deleteById(cloudFileRoleVo.getId()); + } + + if(null!=data.getIds()){ + for (Integer userId:data.getIds()) { + CloudFileRole cloudFileRole = new CloudFileRole(); + cloudFileRole.setFileId(updateData.getId()); + cloudFileRole.setUserId(userId); + cloudFileRoleMapper.insert(cloudFileRole); + } + } + + + + return 1; + } + return 0; + } + @Override + public int recover(String id) { + LocalDateTime localDateTime = LocalDateTime.now(); + + CloudFile updateData = cloudFileMapper.selectById(id); + updateData.setDeleteId(null); + updateData.setDeleteName(null); + updateData.setDeleteTime(null); + + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + updateData.setUpdateTime(localDateTime); + updateData.setUpdaterId(sysUser.getId()); + updateData.setUpdaterName(sysUser.getUsername()); + if(cloudFileMapper.updateById(updateData)==1){ + + ReqCloudFileTrace reqCloudFileTrace = new ReqCloudFileTrace(); + reqCloudFileTrace.setFileId(id); + reqCloudFileTrace.setTraceName("恢复了 "+updateData.getFileName()+" 文件"); + iCloudFileTraceService.saveData(reqCloudFileTrace); + + return 1; + } + return 0; + } + @Override + public int deleteById(String id) { + if (null == id) { + throw new ServiceException("删除的ID不能为空!"); + } + LocalDateTime localDateTime = LocalDateTime.now(); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + CloudFile data = cloudFileMapper.selectById(id); + if(null!=data){ + data.setDeleteId(sysUser.getId()); + data.setDeleteName(sysUser.getUsername()); + data.setDeleteTime(localDateTime); + + + ReqCloudFileTrace reqCloudFileTrace = new ReqCloudFileTrace(); + reqCloudFileTrace.setFileId(id); + reqCloudFileTrace.setTraceName("删除了 "+data.getFileName()+" 文件"); + iCloudFileTraceService.saveData(reqCloudFileTrace); + return cloudFileMapper.updateById(data); + }else{ + return 0; + } + } + + @Override + public int[] changeDeleteStatus(Integer newStatus, String[] ids) { + /// 信息不能为空 + if (null == newStatus || null == ids) { + throw new ServiceException("新状态或ID不能为空"); + } + // 新状态只能为 0 | 1 + if (newStatus == 0 || newStatus == 1) { + int[] result = new int[2]; + for (String id : ids) { + CloudFile data = cloudFileMapper.selectById(id); + data.setFileTop(newStatus); + if (cloudFileMapper.updateById(data) > 0) { + result[0]++; + } else result[1]++; + } + // 返回结果 + return result; + } else { + throw new ServiceException("新状态只能为0或1!"); + } + } + + @Override + public PageList queryByIndexPage(Integer page, Integer limit, ReqCloudFile data) { + Integer pages = limit * (page - 1); + ArrayList list = cloudFileMapper.queryByIndexPage(pages, limit,data); + Integer count = cloudFileMapper.queryByIndexPageCount(data); + return new PageList(list,page,limit,count); + } + + + @Override + public List queryFileByData(ReqCloudFile data) { + return cloudFileMapper.queryFileByData(data); + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/trace/CloudFileTraceServiceImpl.java b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/trace/CloudFileTraceServiceImpl.java new file mode 100644 index 0000000..7e72543 --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/service/impl/cloud/trace/CloudFileTraceServiceImpl.java @@ -0,0 +1,59 @@ +package com.zxdmy.excite.system.service.impl.cloud.trace; + +import cn.dev33.satoken.stp.StpUtil; +import com.zxdmy.excite.common.entity.PageList; +import com.zxdmy.excite.system.entity.SysUser; +import com.zxdmy.excite.system.entity.cloud.lately.CloudUserLately; +import com.zxdmy.excite.system.entity.cloud.trace.CloudFileTrace; +import com.zxdmy.excite.system.entity.req.lately.ReqCloudUserLately; +import com.zxdmy.excite.system.entity.req.trace.ReqCloudFileTrace; +import com.zxdmy.excite.system.entity.vo.space.CloudFileVo; +import com.zxdmy.excite.system.entity.vo.trace.CloudFileTraceVo; +import com.zxdmy.excite.system.mapper.SysUserMapper; +import com.zxdmy.excite.system.mapper.cloud.trace.CloudFileTraceMapper; +import com.zxdmy.excite.system.service.cloud.trace.ICloudFileTraceService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; + +/** + *

                          + * 文件痕迹 服务实现类 + *

                          + * + * @author 沈松 + * @since 2026-01-29 + */ +@Service +@AllArgsConstructor +public class CloudFileTraceServiceImpl extends ServiceImpl implements ICloudFileTraceService { + CloudFileTraceMapper cloudFileTraceMapper; + SysUserMapper sysUserMapper; + + @Override + public PageList queryByPage(Integer page, Integer limit, ReqCloudFileTrace data) { + Integer pages = limit * (page - 1); + ArrayList list = cloudFileTraceMapper.queryByPage(pages, limit,data); + Integer count = cloudFileTraceMapper.queryByPageCount(data); + return new PageList(list,page,limit,count); + } + + @Override + public int saveData(ReqCloudFileTrace data) { + LocalDateTime localDateTime = LocalDateTime.now(); + CloudFileTrace saveData = new CloudFileTrace(); + SysUser sysUser = sysUserMapper.selectById(StpUtil.getLoginIdAsInt()); + saveData.setTraceName(data.getTraceName()); + saveData.setFileId(Long.valueOf(data.getFileId())); + saveData.setTraceCreatorId(sysUser.getId()); + saveData.setTraceCreatorName(sysUser.getUsername()); + saveData.setCreateTime(localDateTime); + if(cloudFileTraceMapper.insert(saveData)==1){ + return 1; + } + return 0; + } +} diff --git a/ss-system/src/main/java/com/zxdmy/excite/system/utils/AuthUtils.java b/ss-system/src/main/java/com/zxdmy/excite/system/utils/AuthUtils.java new file mode 100644 index 0000000..82ff1ee --- /dev/null +++ b/ss-system/src/main/java/com/zxdmy/excite/system/utils/AuthUtils.java @@ -0,0 +1,147 @@ +package com.zxdmy.excite.system.utils; + +import com.zxdmy.excite.common.config.ExciteConfig; +import com.zxdmy.excite.common.service.RedisService; +import com.zxdmy.excite.system.entity.SysMenu; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.io.Serializable; +import java.util.List; + +/** + * 授权工具类(权限清理工具) + * + * @author 沈松 + * @since 2022/1/20 17:34 + */ +@Component +@AllArgsConstructor +public class AuthUtils { + + private RedisService redisService1; + + private ExciteConfig exciteConfig1; + + private static RedisService redisService; + + private static ExciteConfig exciteConfig; + + @PostConstruct + public void init() { + redisService = redisService1; + exciteConfig = exciteConfig1; + } + + /** + * 系统权限列表 默认 KEY + */ + private static final String SYSTEM_MENUS_KEY = "menu:systemMenuList"; + + /** + * 用户权限列表 默认 KEY的 前缀 + */ + private static final String USER_MENU_KEY = "menu:userMenuList:"; + + + /** + * 保存【系统权限列表】至缓存 + * + * @param isSuccess 执行条件 + * @param menuList 菜单列表 + */ + public static void setSystemMenuListCache(boolean isSuccess, List menuList) { + if (exciteConfig.getAllowRedis() && isSuccess) { + redisService.set(SYSTEM_MENUS_KEY, (Serializable) menuList); + } + } + + /** + * 保存【用户权限列表】至缓存 + * + * @param isSuccess 执行条件 + * @param userId 用户ID + * @param menuList 权限列表 + */ + public static void setUserMenuListCache(boolean isSuccess, Integer userId, List menuList) { + if (exciteConfig.getAllowRedis() && isSuccess) { + redisService.set(USER_MENU_KEY + userId, (Serializable) menuList, 7200L); + } + } + + /** + * 从缓存读取【系统权限列表】 + * + * @param isSuccess 执行条件 + * @return 结果:null | List + */ + public static List getSystemMenuListCache(boolean isSuccess) { + if (exciteConfig.getAllowRedis() && isSuccess) { + return (List) redisService.get(SYSTEM_MENUS_KEY); + } + return null; + } + + /** + * 从缓存读取【用户权限列表】 + * + * @param isSuccess 执行条件 + * @param userId 用户ID + * @return 结果:null | List + */ + public static List getUserMenuListCache(boolean isSuccess, Integer userId) { + if (exciteConfig.getAllowRedis() && isSuccess) { + return (List) redisService.get(USER_MENU_KEY + userId); + } + return null; + } + + /** + * 清除【系统权限列表】的缓存 + * + * @param isSuccess 执行条件,为真则执行 + */ + public static void clearSystemMenuListCache(boolean isSuccess) { + if (exciteConfig.getAllowRedis() && isSuccess) { + redisService.remove(SYSTEM_MENUS_KEY); + } + } + + /** + * 清除全部【用户权限列表】的缓存 + * + * @param isSuccess 执行条件,为真则执行 + */ + public static void clearUserMenuListCache(boolean isSuccess) { + if (exciteConfig.getAllowRedis() && isSuccess) { + redisService.removeByPrefix(USER_MENU_KEY); + } + } + + /** + * 清除指定【用户权限列表】的缓存 + * + * @param isSuccess 执行条件,为真则执行 + * @param userId 要清除的用户ID + */ + public static void clearUserMenuListCacheById(boolean isSuccess, Integer userId) { + if (exciteConfig.getAllowRedis() && isSuccess) { + redisService.remove(USER_MENU_KEY + userId); + } + } + + /** + * 清除指定【用户权限列表】的缓存(批量删除) + * + * @param isSuccess 执行条件,为真则执行 + * @param userIds 要清除的用户ID列表 + */ + public static void clearUserMenuListCacheById(boolean isSuccess, Integer[] userIds) { + if (exciteConfig.getAllowRedis() && isSuccess && userIds.length > 0) { + for (int userId : userIds) { + redisService.remove(USER_MENU_KEY + userId); + } + } + } +} diff --git a/ss-system/src/main/resources/mapper/SysLogLoginMapper.xml b/ss-system/src/main/resources/mapper/SysLogLoginMapper.xml new file mode 100644 index 0000000..cd115d2 --- /dev/null +++ b/ss-system/src/main/resources/mapper/SysLogLoginMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + id, user_id, user_account, ip, user_agent, req_data, res_data, time_cost, status, create_time, update_time, delete_time + + + diff --git a/ss-system/src/main/resources/mapper/SysLogRequestMapper.xml b/ss-system/src/main/resources/mapper/SysLogRequestMapper.xml new file mode 100644 index 0000000..8179989 --- /dev/null +++ b/ss-system/src/main/resources/mapper/SysLogRequestMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + id + , user_id, ip, user_agent, req_uri, req_method, req_function, req_data, res_data, time_cost, status, create_time, update_time, delete_time + + + diff --git a/ss-system/src/main/resources/mapper/SysMenuMapper.xml b/ss-system/src/main/resources/mapper/SysMenuMapper.xml new file mode 100644 index 0000000..f126a9e --- /dev/null +++ b/ss-system/src/main/resources/mapper/SysMenuMapper.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + id + , name, icon, path, permission, component, parent_id, type, sort, editable, removable, status, is_delete, create_time, update_time, delete_time + + + + + + + + + + diff --git a/ss-system/src/main/resources/mapper/SysRoleMapper.xml b/ss-system/src/main/resources/mapper/SysRoleMapper.xml new file mode 100644 index 0000000..658e76a --- /dev/null +++ b/ss-system/src/main/resources/mapper/SysRoleMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + id, name, permission, remark, sort, status,upload_role,down_role, is_delete, create_time, update_time, delete_time + + + diff --git a/ss-system/src/main/resources/mapper/SysRoleMenuMapper.xml b/ss-system/src/main/resources/mapper/SysRoleMenuMapper.xml new file mode 100644 index 0000000..f7a456c --- /dev/null +++ b/ss-system/src/main/resources/mapper/SysRoleMenuMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + id, role_id, menu_id + + + diff --git a/ss-system/src/main/resources/mapper/SysUserMapper.xml b/ss-system/src/main/resources/mapper/SysUserMapper.xml new file mode 100644 index 0000000..0a043ff --- /dev/null +++ b/ss-system/src/main/resources/mapper/SysUserMapper.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + id + , username, avatar, sex, login_name, phone, password, remark, status, login_ip, login_date, is_delete, create_time, update_time, delete_time + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ss-system/src/main/resources/mapper/SysUserRoleMapper.xml b/ss-system/src/main/resources/mapper/SysUserRoleMapper.xml new file mode 100644 index 0000000..ef9f6d6 --- /dev/null +++ b/ss-system/src/main/resources/mapper/SysUserRoleMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + id, user_id, role_id + + + diff --git a/ss-system/src/main/resources/mapper/cloud/account/CloudCompanyMapper.xml b/ss-system/src/main/resources/mapper/cloud/account/CloudCompanyMapper.xml new file mode 100644 index 0000000..f47f84a --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/account/CloudCompanyMapper.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + id, company_name, company_sort, create_time, creator_id, creator_name, delete_time, delete_id, delete_name + + + + + + + + + + + + + + + diff --git a/ss-system/src/main/resources/mapper/cloud/account/CloudDepartmentMapper.xml b/ss-system/src/main/resources/mapper/cloud/account/CloudDepartmentMapper.xml new file mode 100644 index 0000000..a8744af --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/account/CloudDepartmentMapper.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + id, department_name, department_sort, department_parent_id,company_id, create_time, creator_id, creator_name, delete_time, delete_id, delete_name + + + + + + + + + + + + + + + diff --git a/ss-system/src/main/resources/mapper/cloud/account/CloudDepartmentUserMapper.xml b/ss-system/src/main/resources/mapper/cloud/account/CloudDepartmentUserMapper.xml new file mode 100644 index 0000000..d108ec9 --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/account/CloudDepartmentUserMapper.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + id, department_id, user_id + + + + + diff --git a/ss-system/src/main/resources/mapper/cloud/collection/CloudUserCollectionMapper.xml b/ss-system/src/main/resources/mapper/cloud/collection/CloudUserCollectionMapper.xml new file mode 100644 index 0000000..c5247fa --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/collection/CloudUserCollectionMapper.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + id, file_id, user_id, create_time + + + + + + + + + diff --git a/ss-system/src/main/resources/mapper/cloud/lately/CloudUserLatelyMapper.xml b/ss-system/src/main/resources/mapper/cloud/lately/CloudUserLatelyMapper.xml new file mode 100644 index 0000000..e56a6c9 --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/lately/CloudUserLatelyMapper.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + id, file_id, user_id, create_time, lately_time + + + + + + + + + + diff --git a/ss-system/src/main/resources/mapper/cloud/role/CloudRoleFileMapper.xml b/ss-system/src/main/resources/mapper/cloud/role/CloudRoleFileMapper.xml new file mode 100644 index 0000000..97b2c41 --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/role/CloudRoleFileMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + id, role_id, file_id + + + diff --git a/ss-system/src/main/resources/mapper/cloud/role/CloudRoleMapper.xml b/ss-system/src/main/resources/mapper/cloud/role/CloudRoleMapper.xml new file mode 100644 index 0000000..9697bf2 --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/role/CloudRoleMapper.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + id, role_name, role_upload, role_down,role_delete, create_time, creator_id, creator_name, delete_time, delete_id, delete_name + + + + + + + + + + + + diff --git a/ss-system/src/main/resources/mapper/cloud/role/CloudRoleUserMapper.xml b/ss-system/src/main/resources/mapper/cloud/role/CloudRoleUserMapper.xml new file mode 100644 index 0000000..b778652 --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/role/CloudRoleUserMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + id, role_id, user_id + + + diff --git a/ss-system/src/main/resources/mapper/cloud/space/CloudFileMapper.xml b/ss-system/src/main/resources/mapper/cloud/space/CloudFileMapper.xml new file mode 100644 index 0000000..fb191f5 --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/space/CloudFileMapper.xml @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, file_name, file_size, file_format, file_oss, file_image, file_sort, file_folder, file_parent_id, file_top_id, file_folder_path, create_time, creator_id, creator_name, update_time, updater_id, updater_name, delete_time, delete_id, delete_name,file_top + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ss-system/src/main/resources/mapper/cloud/space/CloudFileRoleMapper.xml b/ss-system/src/main/resources/mapper/cloud/space/CloudFileRoleMapper.xml new file mode 100644 index 0000000..ef38954 --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/space/CloudFileRoleMapper.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + id, file_id, user_id + + + + + + + + + + diff --git a/ss-system/src/main/resources/mapper/cloud/trace/CloudFileTraceMapper.xml b/ss-system/src/main/resources/mapper/cloud/trace/CloudFileTraceMapper.xml new file mode 100644 index 0000000..709a3a9 --- /dev/null +++ b/ss-system/src/main/resources/mapper/cloud/trace/CloudFileTraceMapper.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + id, trace_name, trace_creator_id, trace_creator_name, create_time, file_id + + + + + + +