From 56322786887f99604450cde07c9cab6fb5ea5135 Mon Sep 17 00:00:00 2001 From: 疯狂的狮子Li <15040126243@163.com> Date: 星期一, 12 七月 2021 11:39:43 +0800 Subject: [PATCH] !67 同步dev分支 Merge pull request !67 from 疯狂的狮子Li/dev --- ruoyi-ui/src/directive/permission/hasPermi.js | 4 ruoyi-ui/src/views/demo/demo/index.vue | 6 ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java | 6 ruoyi-ui/src/views/system/user/index.vue | 39 ruoyi-ui/src/layout/components/InnerLink/index.vue | 27 ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java | 4 ruoyi-admin/src/main/resources/i18n/messages_en_US.properties | 33 ruoyi-quartz/pom.xml | 2 ruoyi-ui/src/views/system/user/authRole.vue | 117 + ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java | 3 ruoyi-ui/.env.production | 3 ruoyi-ui/.env.staging | 3 ruoyi-ui/package.json | 2 ruoyi-ui/src/main.js | 13 ruoyi-ui/src/views/demo/tree/index.vue | 6 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java | 4 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java | 16 ruoyi-demo/src/main/java/com/ruoyi/demo/feign/fallback/FeignTestFallback.java | 3 ruoyi-ui/src/router/index.js | 27 ruoyi-extend/ruoyi-monitor-admin/pom.xml | 73 ruoyi-ui/src/directive/permission/hasRole.js | 4 sql/ry_20210210.sql | 4 ruoyi-ui/src/views/system/role/authUser.vue | 213 ++ ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java | 70 ruoyi-framework/src/main/java/com/ruoyi/framework/config/FeignConfig.java | 36 ruoyi-ui/src/views/system/notice/index.vue | 4 ruoyi-generator/src/main/resources/vm/vue/index.vue.vm | 48 ruoyi-ui/vue.config.js | 2 ruoyi-admin/Dockerfile | 14 ruoyi-generator/pom.xml | 2 ruoyi-ui/src/directive/dialog/drag.js | 64 ruoyi-admin/src/main/resources/application.yml | 55 README.md | 21 ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java | 41 ruoyi-extend/pom.xml | 18 ruoyi-ui/src/directive/index.js | 18 ruoyi-admin/src/main/resources/application-prod.yml | 31 ruoyi-extend/ruoyi-monitor-admin/Dockerfile | 13 ruoyi-ui/.env.development | 3 ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java | 12 ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java | 5 ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java | 48 ruoyi-admin/src/main/resources/application-dev.yml | 27 docker/nginx/nginx.conf | 77 ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml | 45 ruoyi-ui/src/components/Editor/index.vue | 13 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java | 24 ruoyi-ui/src/views/index.vue | 26 ruoyi-ui/src/views/system/role/index.vue | 38 ruoyi-ui/src/layout/components/AppMain.vue | 2 ruoyi-ui/src/views/monitor/admin/index.vue | 20 pom.xml | 21 ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties | 36 ruoyi-ui/src/api/system/user.js | 17 ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java | 12 ruoyi-ui/src/components/TopNav/index.vue | 4 docker/docker-compose.yml | 119 + ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java | 2144 ++++++++++++------------ ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java | 30 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java | 27 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java | 38 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java | 29 ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/AdminServerConfig.java | 31 ruoyi-ui/src/views/system/role/selectUser.vue | 142 + ruoyi-ui/src/store/modules/permission.js | 3 ruoyi-framework/pom.xml | 2 ruoyi-admin/pom.xml | 25 ruoyi-system/pom.xml | 2 ruoyi-ui/src/api/system/role.js | 48 ruoyi-ui/src/components/HeaderSearch/index.vue | 4 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java | 9 ruoyi-ui/src/components/ImageUpload/index.vue | 198 + ruoyi-common/pom.xml | 6 ruoyi-ui/src/assets/styles/ruoyi.scss | 18 ruoyi-generator/src/main/resources/vm/java/mapper.java.vm | 2 ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java | 28 /dev/null | 15 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java | 38 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java | 67 ruoyi-demo/pom.xml | 4 ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/MonitorAdminApplication.java | 19 ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm | 46 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java | 57 docker/deploy.sh | 92 + ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java | 8 ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java | 34 ruoyi-ui/src/components/FileUpload/index.vue | 77 ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java | 31 ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml | 11 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java | 68 90 files changed, 3,526 insertions(+), 1,425 deletions(-) diff --git a/README.md b/README.md index 5fc29ab..a56dc6c 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,17 @@ [](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/blob/master/LICENSE) [ <br> -[](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus) +[](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus) []() []() []() -鍩轰簬 RuoYi-Vue 闆嗘垚 Mybatis-Plus Lombok Hutool 绛変究鎹峰紑鍙戝伐鍏� 閫傞厤閲嶅啓鐩稿叧涓氬姟 渚夸簬寮�鍙� 瀹氭湡涓� RuoYi-Vue 鍚屾 +RuoYi-Vue-Plus 鏄熀浜� RuoYi-Vue 閽堝 `鍒嗗竷寮忛泦缇 鍦烘櫙鍗囩骇 瀹氭湡涓� RuoYi-Vue 鍚屾 + +闆嗘垚 Lock4j dynamic-datasource 绛夊垎甯冨紡鍦烘櫙瑙e喅鏂规 + +闆嗘垚 Mybatis-Plus Lombok Hutool 绛変究鎹峰紑鍙戝伐鍏� 閫傞厤閲嶅啓鐩稿叧涓氬姟 渚夸簬寮�鍙� + * 鍓嶇寮�鍙戞鏋� Vue銆丒lement UI * 鍚庣寮�鍙戞鏋� Spring Boot銆丷edis * 瀹瑰櫒妗嗘灦 Undertow 鍩轰簬 Netty 鐨勯珮鎬ц兘瀹瑰櫒 @@ -27,12 +32,15 @@ * 澶氭暟鎹簮妗嗘灦 dynamic-datasource 鏀寔涓讳粠涓庡绉嶇被鏁版嵁搴撳紓鏋� * Redis瀹㈡埛绔� 閲囩敤 Redisson 鎬ц兘鏇村己 * 鍒嗗竷寮忛攣 Lock4j 娉ㄨВ閿併�佸伐鍏烽攣 澶氱澶氭牱 +* 閮ㄧ讲鏂瑰紡 Docker 瀹瑰櫒缂栨帓 涓�閿儴缃蹭笟鍔¢泦缇� ## 鍙傝�冩枃妗� 浣跨敤妗嗘灦鍓嶈浠旂粏闃呰鏂囨。閲嶇偣娉ㄦ剰浜嬮」 <br> >[鍒濆鍖栭」鐩� 蹇呯湅](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍏充簬鍒濆鍖栭」鐩�?sort_id=4164117) +> +>[閮ㄧ讲椤圭洰 蹇呯湅](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/鍏充簬搴旂敤閮ㄧ讲?sort_id=4219382) > >[鍙傝�冩枃妗� Wiki](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages) @@ -58,6 +66,12 @@ ### 鍥涖�佸姞缇� 浠ヤ笂涓夌偣宸茬粡鑳借В鍐冲ぇ瀹剁粷澶ч儴鍒嗛棶棰樹簡锛屽鏋滆繕鏈夐棶棰樻病鑳介�氳繃杩欏嚑绉嶆柟寮忚В鍐筹紝閭d箞鍔犵兢锛屽ぇ瀹朵竴璧峰湪缇ら噷鎺㈣涓�涓� +## 璐$尞浠g爜 + +娆㈣繋鍚勮矾鑻遍泟璞澃 `PR` 浠g爜 璇锋彁浜ゅ埌 `dev` 寮�鍙戝垎鏀� 缁熶竴娴嬭瘯鍙戠増 + +妗嗘灦瀹氫綅涓� `閫氱敤鍚庡彴绠$悊绯荤粺(鍒嗗竷寮忛泦缇ゅ己鍖�)` 鍘熷垯涓婁笉鎺ュ彈涓氬姟 `PR` + ## 淇敼RuoYi鍔熻兘 ### 渚濊禆鏀瑰姩 @@ -74,6 +88,7 @@ * 绉婚櫎 fastjson 缁熶竴浣跨敤 jackson 搴忓垪鍖� * 闆嗘垚 dynamic-datasource 澶氭暟鎹簮(榛樿鏀寔MySQL,鍏朵粬绉嶇被闇�鑷閫傞厤) * 闆嗘垚 Lock4j 瀹炵幇鍒嗗竷寮� 娉ㄨВ閿併�佸伐鍏烽攣 澶氱澶氭牱 +* 澧炲姞 Docker 瀹瑰櫒缂栨帓 鎵撳寘鎻掍欢涓庨儴缃茶剼鏈� ### 浠g爜鏀瑰姩 @@ -90,7 +105,7 @@ ### 鍏朵粬 -* 鍚屾鍗囩骇 RuoYi-Vue 3.5.0 +* 鍚屾鍗囩骇 RuoYi-Vue * GitHub 鍦板潃 [RuoYi-Vue-Plus-github](https://github.com/JavaLionLi/RuoYi-Vue-Plus) * 鍗曟ā鍧� fast 鍒嗘敮 [RuoYi-Vue-Plus-fast](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/fast/) * Oracle 妯″潡 oracle 鍒嗘敮 [RuoYi-Vue-Plus-oracle](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/tree/oracle/) diff --git a/docker/deploy.sh b/docker/deploy.sh new file mode 100644 index 0000000..3b6e696 --- /dev/null +++ b/docker/deploy.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +#浣跨敤璇存槑锛岀敤鏉ユ彁绀鸿緭鍏ュ弬鏁� +usage() { + echo "Usage: sh 鎵ц鑴氭湰.sh [port|mount|monitor|base|start|stop|stopall|rm|rmiNoneTag]" + exit 1 +} + +#寮�鍚墍闇�绔彛 +port(){ + firewall-cmd --add-port=3306/tcp --permanent + firewall-cmd --add-port=6379/tcp --permanent + service firewalld restart +} + +##鏀剧疆鎸傝浇鏂囦欢 +mount(){ + #鎸傝浇閰嶇疆鏂囦欢 + if test ! -f "/docker/nginx/conf/nginx.conf" ;then + mkdir -p /docker/nginx/conf + cp nginx/nginx.conf /docker/nginx/conf/nginx.conf + fi +} + +#鍚姩鍩虹妯″潡 +base(){ + docker-compose up -d mysql nginx-web redis +} + +#鍚姩鍩虹妯″潡 +monitor(){ + docker-compose up -d ruoyi-monitor-admin +} + +#鍚姩绋嬪簭妯″潡 +start(){ + docker-compose up -d ruoyi-server1 ruoyi-server2 +} + +#鍋滄绋嬪簭妯″潡 +stop(){ + docker-compose stop ruoyi-server1 ruoyi-server2 +} + +#鍏抽棴鎵�鏈夋ā鍧� +stopall(){ + docker-compose stop +} + +#鍒犻櫎鎵�鏈夋ā鍧� +rm(){ + docker-compose rm +} + +#鍒犻櫎Tag涓虹┖鐨勯暅鍍� +rmiNoneTag(){ + docker images|grep none|awk '{print $3}'|xargs docker rmi -f +} + +#鏍规嵁杈撳叆鍙傛暟锛岄�夋嫨鎵ц瀵瑰簲鏂规硶锛屼笉杈撳叆鍒欐墽琛屼娇鐢ㄨ鏄� +case "$1" in +"port") + port +;; +"mount") + mount +;; +"base") + base +;; +"monitor") + monitor +;; +"start") + start +;; +"stop") + stop +;; +"stopall") + stopall +;; +"rm") + rm +;; +"rmiNoneTag") + rmiNoneTag +;; +*) + usage +;; +esac diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..d40ae29 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,119 @@ +version: '3' + +services: + mysql: + image: mysql:8.0.24 + container_name: mysql + environment: + # 鏃跺尯涓婃捣 + TZ: Asia/Shanghai + # root 瀵嗙爜 + MYSQL_ROOT_PASSWORD: root + # 鍒濆鍖栨暟鎹簱(鍚庣画鐨勫垵濮嬪寲sql浼氬湪杩欎釜搴撴墽琛�) + MYSQL_DATABASE: ry-vue + ports: + - 3306:3306 + volumes: + # 鏁版嵁鎸傝浇 + - /docker/mysql/data/:/var/lib/mysql/ + # 閰嶇疆鎸傝浇 + - /docker/mysql/conf/:/etc/mysql/conf.d/ + command: + # 灏唌ysql8.0榛樿瀵嗙爜绛栫暐 淇敼涓� 鍘熷厛 绛栫暐 (mysql8.0瀵瑰叾榛樿绛栫暐鍋氫簡鏇存敼 浼氬鑷村瘑鐮佹棤娉曞尮閰�) + --default-authentication-plugin=mysql_native_password + --character-set-server=utf8mb4 + --collation-server=utf8mb4_general_ci + --explicit_defaults_for_timestamp=true + --lower_case_table_names=1 + privileged: true + restart: always + networks: + ruoyi_net: + ipv4_address: 172.30.0.36 + + nginx-web: + # 濡傛灉闇�瑕佹寚瀹氱増鏈� 灏辨妸 latest 鎹㈡垚鐗堟湰鍙� + image: nginx:latest + container_name: nginx-web + ports: + - 80:80 + - 443:443 + volumes: + # 璇佷功鏄犲皠 + - /docker/nginx/cert:/etc/nginx/cert + # 閰嶇疆鏂囦欢鏄犲皠 + - /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf + # 椤甸潰鐩綍 + - /docker/nginx/html:/usr/share/nginx/html + # 鏃ュ織鐩綍 + - /docker/nginx/log:/var/log/nginx + # 涓绘満鏈満鏃堕棿鏂囦欢鏄犲皠 涓庢湰鏈烘椂闂村悓姝� + - /etc/localtime:/etc/localtime:ro + privileged: true + restart: always + networks: + - ruoyi_net + + redis: + image: redis:6.2.1 + container_name: redis + ports: + - 6379:6379 + environment: + # 璁剧疆鐜鍙橀噺 鏃跺尯涓婃捣 缂栫爜UTF-8 + TZ: Asia/Shanghai + LANG: en_US.UTF-8 + volumes: + # 閰嶇疆鏂囦欢 + - /docker/redis/conf/redis.conf:/redis.conf:rw + # 鏁版嵁鏂囦欢 + - /docker/redis/data:/data:rw + command: "redis-server --appendonly yes" + privileged: true + restart: always + networks: + ruoyi_net: + ipv4_address: 172.30.0.48 + + ruoyi-server1: + image: "ruoyi/ruoyi-server:2.5.0" + environment: + - TZ=Asia/Shanghai + volumes: + # 閰嶇疆鏂囦欢 + - /docker/server1/logs/:/ruoyi/server/logs/ + privileged: true + restart: always + networks: + ruoyi_net: + ipv4_address: 172.30.0.60 + + ruoyi-server2: + image: "ruoyi/ruoyi-server:2.5.0" + environment: + - TZ=Asia/Shanghai + volumes: + # 閰嶇疆鏂囦欢 + - /docker/server2/logs/:/ruoyi/server/logs/ + privileged: true + restart: always + networks: + ruoyi_net: + ipv4_address: 172.30.0.61 + + ruoyi-monitor-admin: + image: "ruoyi/ruoyi-monitor-admin:2.5.0" + environment: + - TZ=Asia/Shanghai + privileged: true + restart: always + networks: + ruoyi_net: + ipv4_address: 172.30.0.90 + +networks: + ruoyi_net: + driver: bridge + ipam: + config: + - subnet: 172.30.0.0/16 diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf new file mode 100644 index 0000000..66ac29e --- /dev/null +++ b/docker/nginx/nginx.conf @@ -0,0 +1,77 @@ +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + # 闄愬埗body澶у皬 + client_max_body_size 100m; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + upstream server { + server 172.30.0.60:8080; + server 172.30.0.61:8080; + } + + upstream monitor-admin { + server 172.30.0.90:9090; + } + + server { + listen 80; + server_name localhost; + + # https閰嶇疆鍙傝�� start + #listen 443 ssl; + + # 璇佷功鐩存帴瀛樻斁 /docker/nginx/cert/ 鐩綍涓嬪嵆鍙� 鏇存敼璇佷功鍚嶇О鍗冲彲 鏃犻渶鏇存敼璇佷功璺緞 + #ssl on; + #ssl_certificate /etc/nginx/cert/xxx.local.crt; # /etc/nginx/cert/ 涓篸ocker鏄犲皠璺緞 涓嶅厑璁告洿鏀� + #ssl_certificate_key /etc/nginx/cert/xxx.local.key; # /etc/nginx/cert/ 涓篸ocker鏄犲皠璺緞 涓嶅厑璁告洿鏀� + #ssl_session_timeout 5m; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; + #ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + #ssl_prefer_server_ciphers on; + # https閰嶇疆鍙傝�� end + + location / { + root /usr/share/nginx/html; + try_files $uri $uri/ /index.html; + index index.html index.htm; + } + + location /prod-api/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://server/; + } + + location /admin/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://monitor-admin/admin/; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + } +} diff --git a/pom.xml b/pom.xml index 2a8521c..d56898b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,32 +6,38 @@ <groupId>com.ruoyi</groupId> <artifactId>ruoyi-vue-plus</artifactId> - <version>${ruoyi-vue-plus.version}</version> + <version>2.5.0</version> <name>RuoYi-Vue-Plus</name> <url>https://gitee.com/JavaLionLi/RuoYi-Vue-Plus</url> <description>RuoYi-Vue-Plus鍚庡彴绠$悊绯荤粺</description> <properties> - <ruoyi-vue-plus.version>2.4.0</ruoyi-vue-plus.version> - <spring-boot.version>2.4.7</spring-boot.version> + <ruoyi-vue-plus.version>2.5.0</ruoyi-vue-plus.version> + <spring-boot.version>2.4.8</spring-boot.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> <druid.version>1.2.6</druid.version> - <knife4j.version>3.0.2</knife4j.version> + <knife4j.version>3.0.3</knife4j.version> <poi.version>4.1.2</poi.version> <velocity.version>1.7</velocity.version> <jwt.version>0.9.1</jwt.version> <mybatis-plus.version>3.4.3</mybatis-plus.version> - <hutool.version>5.7.2</hutool.version> + <hutool.version>5.7.4</hutool.version> <feign.version>3.0.3</feign.version> <feign-okhttp.version>11.0</feign-okhttp.version> - <spring-boot-admin.version>2.4.1</spring-boot-admin.version> - <redisson.version>3.15.2</redisson.version> + <spring-boot-admin.version>2.4.3</spring-boot-admin.version> + <redisson.version>3.16.0</redisson.version> <lock4j.version>2.2.1</lock4j.version> <datasource.version>3.4.0</datasource.version> + + <!-- docker 閰嶇疆 --> + <docker.registry.url>localhost</docker.registry.url> + <docker.registry.host>http://${docker.registry.url}:2375</docker.registry.host> + <docker.namespace>ruoyi</docker.namespace> + <docker.plugin.version>1.2.0</docker.plugin.version> </properties> <!-- 渚濊禆澹版槑 --> @@ -192,6 +198,7 @@ <module>ruoyi-generator</module> <module>ruoyi-common</module> <module>ruoyi-demo</module> + <module>ruoyi-extend</module> </modules> <packaging>pom</packaging> diff --git a/ruoyi-admin/Dockerfile b/ruoyi-admin/Dockerfile new file mode 100644 index 0000000..88f4932 --- /dev/null +++ b/ruoyi-admin/Dockerfile @@ -0,0 +1,14 @@ +FROM anapsix/alpine-java:8_server-jre_unlimited + +MAINTAINER Lion Li + +RUN mkdir -p /ruoyi/server +RUN mkdir -p /ruoyi/server/logs + +WORKDIR /ruoyi/server + +EXPOSE 8080 + +ADD ./target/ruoyi-admin.jar ./app.jar + +ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 031427f..7450213 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -5,7 +5,7 @@ <parent> <artifactId>ruoyi-vue-plus</artifactId> <groupId>com.ruoyi</groupId> - <version>${ruoyi-vue-plus.version}</version> + <version>2.5.0</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>jar</packaging> @@ -24,7 +24,7 @@ <optional>true</optional> <!-- 琛ㄧず渚濊禆涓嶄細浼犻�� --> </dependency> - <!-- Mysql椹卞姩鍖� --> + <!-- Mysql椹卞姩鍖� --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> @@ -82,7 +82,26 @@ <failOnMissingWebXml>false</failOnMissingWebXml> <warName>${project.artifactId}</warName> </configuration> - </plugin> + </plugin> + <plugin> + <groupId>com.spotify</groupId> + <artifactId>docker-maven-plugin</artifactId> + <version>${docker.plugin.version}</version> + <configuration> + <imageName>${docker.namespace}/ruoyi-server:${project.version}</imageName> + <dockerDirectory>${project.basedir}</dockerDirectory> + <dockerHost>${docker.registry.host}</dockerHost> + <registryUrl>${docker.registry.url}</registryUrl> + <serverId>${docker.registry.url}</serverId> + <resources> + <resource> + <targetPath>/</targetPath> + <directory>${project.build.directory}</directory> + <include>${project.build.finalName}.jar</include> + </resource> + </resources> + </configuration> + </plugin> </plugins> </build> diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java new file mode 100644 index 0000000..a29620c --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java @@ -0,0 +1,29 @@ +package com.ruoyi.web.controller.system; + +import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.config.RuoYiConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 棣栭〉 + * + * @author ruoyi + */ +@RestController +public class SysIndexController +{ + /** 绯荤粺鍩虹閰嶇疆 */ + @Autowired + private RuoYiConfig ruoyiConfig; + + /** + * 璁块棶棣栭〉锛屾彁绀鸿 + */ + @RequestMapping("/") + public String index() + { + return StrUtil.format("娆㈣繋浣跨敤{}鍚庡彴绠$悊妗嗘灦锛屽綋鍓嶇増鏈細v{}锛岃閫氳繃鍓嶇鍦板潃璁块棶銆�", ruoyiConfig.getName(), ruoyiConfig.getVersion()); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java index 00f1464..f418541 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java @@ -1,8 +1,6 @@ package com.ruoyi.web.controller.system; -import cn.hutool.core.util.StrUtil; import com.ruoyi.common.annotation.Log; -import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; @@ -11,6 +9,7 @@ import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.web.service.TokenService; import com.ruoyi.system.service.ISysMenuService; import org.springframework.beans.factory.annotation.Autowired; @@ -98,8 +97,7 @@ { return AjaxResult.error("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪"); } - else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) - && !StrUtil.startWithAny(menu.getPath(), Constants.HTTP, Constants.HTTPS)) + else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { return AjaxResult.error("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�"); } @@ -119,8 +117,7 @@ { return AjaxResult.error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪"); } - else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) - && !StrUtil.startWithAny(menu.getPath(), Constants.HTTP, Constants.HTTPS)) + else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { return AjaxResult.error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�"); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java index 70e640e..5701aa1 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java @@ -6,6 +6,7 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysRole; +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; @@ -14,6 +15,7 @@ import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.service.SysPermissionService; import com.ruoyi.framework.web.service.TokenService; +import com.ruoyi.system.domain.SysUserRole; import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.service.ISysUserService; import org.springframework.beans.factory.annotation.Autowired; @@ -25,7 +27,7 @@ /** * 瑙掕壊淇℃伅 - * + * * @author ruoyi */ @RestController @@ -171,4 +173,57 @@ { return AjaxResult.success(roleService.selectRoleAll()); } + + /** + * 鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛� + */ + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/authUser/allocatedList") + public TableDataInfo allocatedList(SysUser user) + { + return userService.selectAllocatedList(user); + } + + /** + * 鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛� + */ + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/authUser/unallocatedList") + public TableDataInfo unallocatedList(SysUser user) + { + return userService.selectUnallocatedList(user); + } + + /** + * 鍙栨秷鎺堟潈鐢ㄦ埛 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancel") + public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole) + { + return toAjax(roleService.deleteAuthUser(userRole)); + } + + /** + * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancelAll") + public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds) + { + return toAjax(roleService.deleteAuthUsers(roleId, userIds)); + } + + /** + * 鎵归噺閫夋嫨鐢ㄦ埛鎺堟潈 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT) + @PutMapping("/authUser/selectAll") + public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds) + { + return toAjax(roleService.insertAuthUsers(roleId, userIds)); + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java index 079c15a..a67615f 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java @@ -196,4 +196,31 @@ user.setUpdateBy(SecurityUtils.getUsername()); return toAjax(userService.updateUserStatus(user)); } + + /** + * 鏍规嵁鐢ㄦ埛缂栧彿鑾峰彇鎺堟潈瑙掕壊 + */ + @PreAuthorize("@ss.hasPermi('system:user:query')") + @GetMapping("/authRole/{userId}") + public AjaxResult authRole(@PathVariable("userId") Long userId) + { + SysUser user = userService.selectUserById(userId); + List<SysRole> roles = roleService.selectRolesByUserId(userId); + Map<String, Object> ajax = new HashMap<>(); + ajax.put("user", user); + ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + return AjaxResult.success(ajax); + } + + /** + * 鐢ㄦ埛鎺堟潈瑙掕壊 + */ + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.GRANT) + @PutMapping("/authRole") + public AjaxResult insertAuthRole(Long userId, Long[] roleIds) + { + userService.insertUserAuth(userId, roleIds); + return success(); + } } diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 35901b5..62312f6 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -110,3 +110,30 @@ subscriptionsPerConnection: 5 # DNS鐩戞祴鏃堕棿闂撮殧锛屽崟浣嶏細姣 dnsMonitoringInterval: 5000 + +--- # 鐩戞帶閰嶇疆 +spring: + boot: + admin: + # Spring Boot Admin Client 瀹㈡埛绔殑鐩稿叧閰嶇疆 + client: + # 璁剧疆 Spring Boot Admin Server 鍦板潃 + url: http://localhost:9090/admin + instance: + prefer-ip: true # 娉ㄥ唽瀹炰緥鏃讹紝浼樺厛浣跨敤 IP + username: ruoyi + password: 123456 + +# Actuator 鐩戞帶绔偣鐨勯厤缃」 +management: + endpoints: + web: + # Actuator 鎻愪緵鐨� API 鎺ュ彛鐨勬牴鐩綍銆傞粯璁や负 /actuator + base-path: /actuator + exposure: + # 闇�瑕佸紑鏀剧殑绔偣銆傞粯璁ゅ�煎彧鎵撳紑 health 鍜� info 涓や釜绔偣銆傞�氳繃璁剧疆 * 锛屽彲浠ュ紑鏀炬墍鏈夌鐐广�� + # 鐢熶骇鐜涓嶅缓璁斁寮�鎵�鏈� 鏍规嵁椤圭洰闇�姹傛斁寮�鍗冲彲 + include: '*' + endpoint: + logfile: + external-file: ./logs/sys-console.log diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index 35901b5..2c9d4e5 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -12,7 +12,7 @@ # 涓诲簱鏁版嵁婧� master: driverClassName: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true + url: jdbc:mysql://172.30.0.36:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true username: root password: root # 浠庡簱鏁版嵁婧� @@ -66,7 +66,7 @@ # redis 閰嶇疆 redis: # 鍦板潃 - host: localhost + host: 172.30.0.48 # 绔彛锛岄粯璁や负6379 port: 6379 # 鏁版嵁搴撶储寮� @@ -110,3 +110,30 @@ subscriptionsPerConnection: 5 # DNS鐩戞祴鏃堕棿闂撮殧锛屽崟浣嶏細姣 dnsMonitoringInterval: 5000 + +--- # 鐩戞帶閰嶇疆 +spring: + boot: + admin: + # Spring Boot Admin Client 瀹㈡埛绔殑鐩稿叧閰嶇疆 + client: + # 璁剧疆 Spring Boot Admin Server 鍦板潃 + url: http://172.30.0.90:9090/admin + instance: + prefer-ip: true # 娉ㄥ唽瀹炰緥鏃讹紝浼樺厛浣跨敤 IP + username: ruoyi + password: 123456 + +# Actuator 鐩戞帶绔偣鐨勯厤缃」 +management: + endpoints: + web: + # Actuator 鎻愪緵鐨� API 鎺ュ彛鐨勬牴鐩綍銆傞粯璁や负 /actuator + base-path: /actuator + exposure: + # 闇�瑕佸紑鏀剧殑绔偣銆傞粯璁ゅ�煎彧鎵撳紑 health 鍜� info 涓や釜绔偣銆傞�氳繃璁剧疆 * 锛屽彲浠ュ紑鏀炬墍鏈夌鐐广�� + # 鐢熶骇鐜涓嶅缓璁斁寮�鎵�鏈� 鏍规嵁椤圭洰闇�姹傛斁寮�鍗冲彲 + include: health,info + endpoint: + logfile: + external-file: ./logs/sys-console.log diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index e153d19..b88929d 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -64,6 +64,8 @@ # Spring閰嶇疆 spring: + application: + name: ${ruoyi.name} # 璧勬簮淇℃伅 messages: # 鍥介檯鍖栬祫婧愭枃浠惰矾寰� @@ -110,6 +112,8 @@ # MyBatisPlus閰嶇疆 # https://baomidou.com/config/ mybatis-plus: + # 涓嶆敮鎸佸鍖�, 濡傛湁闇�瑕佸彲鍦ㄦ敞瑙i厤缃� 鎴� 鎻愬崌鎵寘绛夌骇 + # 渚嬪 com.**.**.mapper mapperPackage: com.ruoyi.**.mapper # 瀵瑰簲鐨� XML 鏂囦欢浣嶇疆 mapperLocations: classpath*:mapper/**/*Mapper.xml @@ -156,7 +160,9 @@ # STATEMENT 鍏抽棴涓�绾х紦瀛� localCacheScope: SESSION # 寮�鍚疢ybatis浜岀骇缂撳瓨锛岄粯璁や负 true - cacheEnabled: true + cacheEnabled: false + # 鏇磋缁嗙殑鏃ュ織杈撳嚭 浼氭湁鎬ц兘鎹熻�� + # logImpl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: # 鏄惁鎵撳嵃 Logo banner banner: true @@ -203,7 +209,7 @@ # 璇锋眰鍓嶇紑 pathMapping: /dev-api # 鏍囬 - title: '鏍囬锛歊uoYi-Vue-Plus鍚庡彴绠$悊绯荤粺_鎺ュ彛鏂囨。' + title: '鏍囬锛�${ruoyi.name}鍚庡彴绠$悊绯荤粺_鎺ュ彛鏂囨。' # 鎻忚堪 description: '鎻忚堪锛氱敤浜庣鐞嗛泦鍥㈡棗涓嬪叕鍙哥殑浜哄憳淇℃伅,鍏蜂綋鍖呮嫭XXX,XXX妯″潡...' # 鐗堟湰 @@ -244,6 +250,8 @@ # feign 鐩稿叧閰嶇疆 feign: + # 涓嶆敮鎸佸鍖�, 濡傛湁闇�瑕佸彲鍦ㄦ敞瑙i厤缃� 鎴� 鎻愬崌鎵寘绛夌骇 + # 渚嬪 com.**.**.feign package: com.ruoyi.**.feign # 寮�鍚帇缂� compression: @@ -255,6 +263,21 @@ enabled: true circuitbreaker: enabled: true + +--- # redisson 缂撳瓨閰嶇疆 +redisson: + cacheGroup: + # 鐢ㄤ緥: @Cacheable(cacheNames="groupId", key="#XXX") 鏂瑰彲浣跨敤缂撳瓨缁勯厤缃� + - groupId: redissonCacheMap + # 缁勮繃鏈熸椂闂�(鑴氭湰鐩戞帶) + ttl: 60000 + # 缁勬渶澶х┖闂叉椂闂�(鑴氭湰鐩戞帶) + maxIdleTime: 60000 + # 缁勬渶澶ч暱搴� + maxSize: 0 + - groupId: testCache + ttl: 1000 + maxIdleTime: 500 --- # 鍒嗗竷寮忛攣 lock4j 鍏ㄥ眬閰嶇疆 lock4j: @@ -293,31 +316,3 @@ tablePrefix: QRTZ_ # sqlserver 鍚敤 # selectWithLockSQL: SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ? - ---- # 鐩戞帶閰嶇疆 -spring: - application: - name: ruoyi-vue-plus - boot: - admin: - # Spring Boot Admin Client 瀹㈡埛绔殑鐩稿叧閰嶇疆 - client: - # 璁剧疆 Spring Boot Admin Server 鍦板潃 - url: http://localhost:${server.port}${spring.boot.admin.context-path} - instance: - prefer-ip: true # 娉ㄥ唽瀹炰緥鏃讹紝浼樺厛浣跨敤 IP - # Spring Boot Admin Server 鏈嶅姟绔殑鐩稿叧閰嶇疆 - context-path: /admin # 閰嶇疆 Spring - -# Actuator 鐩戞帶绔偣鐨勯厤缃」 -management: - endpoints: - web: - # Actuator 鎻愪緵鐨� API 鎺ュ彛鐨勬牴鐩綍銆傞粯璁や负 /actuator - base-path: /actuator - exposure: - # 闇�瑕佸紑鏀剧殑绔偣銆傞粯璁ゅ�煎彧鎵撳紑 health 鍜� info 涓や釜绔偣銆傞�氳繃璁剧疆 * 锛屽彲浠ュ紑鏀炬墍鏈夌鐐广�� - include: '*' - endpoint: - logfile: - external-file: ./logs/sys-console.log diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 0000000..4187065 --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,33 @@ +#閿欒娑堟伅 +not.null= +user.jcaptcha.error= +user.jcaptcha.expire= +user.not.exists= +user.password.not.match= +user.password.retry.limit.count= +user.password.retry.limit.exceed= +user.password.delete= +user.blocked= +role.blocked= +user.logout.success= +length.not.valid= +user.username.not.valid= +user.password.not.valid= +user.email.not.valid= +user.mobile.phone.number.not.valid= +user.login.success= +user.notfound= +user.forcelogout= +user.unknown.error= + +##鏂囦欢涓婁紶娑堟伅 +upload.exceed.maxSize= +upload.filename.exceed.length= + +##鏉冮檺 +no.permission= +no.create.permission= +no.update.permission= +no.delete.permission= +no.export.permission= +no.view.permission= diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 0000000..d63aa1f --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,36 @@ +#閿欒娑堟伅 +not.null=* 蹇呴』濉啓 +user.jcaptcha.error=楠岃瘉鐮侀敊璇� +user.jcaptcha.expire=楠岃瘉鐮佸凡澶辨晥 +user.not.exists=鐢ㄦ埛涓嶅瓨鍦�/瀵嗙爜閿欒 +user.password.not.match=鐢ㄦ埛涓嶅瓨鍦�/瀵嗙爜閿欒 +user.password.retry.limit.count=瀵嗙爜杈撳叆閿欒{0}娆� +user.password.retry.limit.exceed=瀵嗙爜杈撳叆閿欒{0}娆★紝甯愭埛閿佸畾10鍒嗛挓 +user.password.delete=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿宸茶鍒犻櫎 +user.blocked=鐢ㄦ埛宸插皝绂侊紝璇疯仈绯荤鐞嗗憳 +role.blocked=瑙掕壊宸插皝绂侊紝璇疯仈绯荤鐞嗗憳 +user.logout.success=閫�鍑烘垚鍔� + +length.not.valid=闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂� + +user.username.not.valid=* 2鍒�20涓眽瀛椼�佸瓧姣嶃�佹暟瀛楁垨涓嬪垝绾跨粍鎴愶紝涓斿繀椤讳互闈炴暟瀛楀紑澶� +user.password.not.valid=* 5-50涓瓧绗� + +user.email.not.valid=閭鏍煎紡閿欒 +user.mobile.phone.number.not.valid=鎵嬫満鍙锋牸寮忛敊璇� +user.login.success=鐧诲綍鎴愬姛 +user.notfound=璇烽噸鏂扮櫥褰� +user.forcelogout=绠$悊鍛樺己鍒堕��鍑猴紝璇烽噸鏂扮櫥褰� +user.unknown.error=鏈煡閿欒锛岃閲嶆柊鐧诲綍 + +##鏂囦欢涓婁紶娑堟伅 +upload.exceed.maxSize=涓婁紶鐨勬枃浠跺ぇ灏忚秴鍑洪檺鍒剁殑鏂囦欢澶у皬锛�<br/>鍏佽鐨勬枃浠舵渶澶уぇ灏忔槸锛歿0}MB锛� +upload.filename.exceed.length=涓婁紶鐨勬枃浠跺悕鏈�闀縶0}涓瓧绗� + +##鏉冮檺 +no.permission=鎮ㄦ病鏈夋暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}] +no.create.permission=鎮ㄦ病鏈夊垱寤烘暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}] +no.update.permission=鎮ㄦ病鏈変慨鏀规暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}] +no.delete.permission=鎮ㄦ病鏈夊垹闄ゆ暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}] +no.export.permission=鎮ㄦ病鏈夊鍑烘暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}] +no.view.permission=鎮ㄦ病鏈夋煡鐪嬫暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}] diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index e2cbd39..28af304 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -5,7 +5,7 @@ <parent> <artifactId>ruoyi-vue-plus</artifactId> <groupId>com.ruoyi</groupId> - <version>${ruoyi-vue-plus.version}</version> + <version>2.5.0</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -116,10 +116,6 @@ <artifactId>feign-okhttp</artifactId> </dependency> - <dependency> - <groupId>de.codecentric</groupId> - <artifactId>spring-boot-admin-starter-server</artifactId> - </dependency> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-client</artifactId> diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java index 56b46ba..eda4ab6 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java @@ -2,7 +2,7 @@ /** * 鐢ㄦ埛甯搁噺淇℃伅 - * + * * @author ruoyi */ public class UserConstants @@ -57,6 +57,9 @@ /** ParentView缁勪欢鏍囪瘑 */ public final static String PARENT_VIEW = "ParentView"; + /** InnerLink缁勪欢鏍囪瘑 */ + public final static String INNER_LINK = "InnerLink"; + /** 鏍¢獙杩斿洖缁撴灉鐮� */ public final static String UNIQUE = "0"; public final static String NOT_UNIQUE = "1"; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java index 110c548..898138b 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java @@ -148,6 +148,10 @@ @TableField(exist = false) private Long[] postIds; + /** 瑙掕壊ID */ + @TableField(exist = false) + private Long roleId; + public SysUser(Long userId) { this.userId = userId; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java index 0e21d70..633a0b5 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java @@ -15,6 +15,9 @@ /** * mybatis-redis 浜岀骇缂撳瓨 * + * 浣跨敤鏂规硶 閰嶇疆鏂囦欢寮�鍚� mybatis-plus 浜岀骇缂撳瓨 + * 鍦� XxxMapper.java 绫讳笂娣诲姞娉ㄨВ @CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class) + * * @author Lion Li */ @Slf4j diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java index 9c8c0f7..ec57621 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/methods/InsertAll.java @@ -1,12 +1,16 @@ package com.ruoyi.common.core.mybatisplus.methods; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.core.enums.SqlMethod; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; +import org.apache.ibatis.executor.keygen.KeyGenerator; import org.apache.ibatis.executor.keygen.NoKeyGenerator; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource; - -import com.baomidou.mybatisplus.core.injector.AbstractMethod; -import com.baomidou.mybatisplus.core.metadata.TableInfo; /** * 鍗晄ql鎵归噺鎻掑叆 @@ -20,9 +24,28 @@ final String sql = "<script>insert into %s %s values %s</script>"; final String fieldSql = prepareFieldSql(tableInfo); final String valueSql = prepareValuesSqlForMysqlBatch(tableInfo); + KeyGenerator keyGenerator = new NoKeyGenerator(); + SqlMethod sqlMethod = SqlMethod.INSERT_ONE; + String keyProperty = null; + String keyColumn = null; + // 琛ㄥ寘鍚富閿鐞嗛�昏緫,濡傛灉涓嶅寘鍚富閿綋鏅�氬瓧娈靛鐞� + if (StrUtil.isNotBlank(tableInfo.getKeyProperty())) { + if (tableInfo.getIdType() == IdType.AUTO) { + /** 鑷涓婚敭 */ + keyGenerator = new Jdbc3KeyGenerator(); + keyProperty = tableInfo.getKeyProperty(); + keyColumn = tableInfo.getKeyColumn(); + } else { + if (null != tableInfo.getKeySequence()) { + keyGenerator = TableInfoHelper.genKeyGenerator(getMethod(sqlMethod), tableInfo, builderAssistant); + keyProperty = tableInfo.getKeyProperty(); + keyColumn = tableInfo.getKeyColumn(); + } + } + } final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql); SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass); - return this.addInsertMappedStatement(mapperClass, modelClass, "insertAll", sqlSource, new NoKeyGenerator(), null, null); + return this.addInsertMappedStatement(mapperClass, modelClass, "insertAll", sqlSource, keyGenerator, keyProperty, keyColumn); } private String prepareFieldSql(TableInfo tableInfo) { diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java index 3c8bc92..f46a215 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java @@ -205,9 +205,9 @@ * @param hKeys Hash閿泦鍚� * @return Hash瀵硅薄闆嗗悎 */ - public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) { - RListMultimap rListMultimap = redissonClient.getListMultimap(key); - return rListMultimap.getAll(hKeys); + public <K,V> Map<K,V> getMultiCacheMapValue(final String key, final Set<K> hKeys) { + RMap<K,V> rMap = redissonClient.getMap(key); + return rMap.getAll(hKeys); } /** diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java index 7da0c66..5d1fef1 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java @@ -88,7 +88,7 @@ StringBuilder propertyString = new StringBuilder(); List<SysDictData> datas = getDictCache(dictType); - if (StrUtil.containsAny(separator, dictValue) && CollUtil.isNotEmpty(datas)) + if (StrUtil.containsAny(dictValue, separator) && CollUtil.isNotEmpty(datas)) { for (SysDictData dict : datas) { @@ -128,7 +128,7 @@ StringBuilder propertyString = new StringBuilder(); List<SysDictData> datas = getDictCache(dictType); - if (StrUtil.containsAny(separator, dictLabel) && CollUtil.isNotEmpty(datas)) + if (StrUtil.containsAny(dictLabel, separator) && CollUtil.isNotEmpty(datas)) { for (SysDictData dict : datas) { diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java new file mode 100644 index 0000000..f3f29f4 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java @@ -0,0 +1,28 @@ +package com.ruoyi.common.utils; + +import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.constant.Constants; + +/** + * 瀛楃涓插伐鍏风被 + * + * @author ruoyi + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils { + /** 绌哄瓧绗︿覆 */ + private static final String NULLSTR = ""; + + /** 涓嬪垝绾� */ + private static final char SEPARATOR = '_'; + + /** + * 鏄惁涓篽ttp(s)://寮�澶� + * + * @param link 閾炬帴 + * @return 缁撴灉 + */ + public static boolean ishttp(String link) { + return StrUtil.startWithAny(link, Constants.HTTP, Constants.HTTPS); + } + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java index 619ec80..96843d1 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java @@ -1,1072 +1,1072 @@ -package com.ruoyi.common.utils.poi; - -import cn.hutool.core.convert.Convert; -import cn.hutool.core.lang.Validator; -import cn.hutool.core.util.StrUtil; -import com.ruoyi.common.annotation.Excel; -import com.ruoyi.common.annotation.Excel.ColumnType; -import com.ruoyi.common.annotation.Excel.Type; -import com.ruoyi.common.annotation.Excels; -import com.ruoyi.common.config.RuoYiConfig; -import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.exception.CustomException; -import com.ruoyi.common.utils.DateUtils; -import com.ruoyi.common.utils.DictUtils; -import com.ruoyi.common.utils.file.FileTypeUtils; -import com.ruoyi.common.utils.file.ImageUtils; -import com.ruoyi.common.utils.reflect.ReflectUtils; -import org.apache.poi.ss.usermodel.*; -import org.apache.poi.ss.util.CellRangeAddressList; -import org.apache.poi.xssf.streaming.SXSSFWorkbook; -import org.apache.poi.xssf.usermodel.XSSFClientAnchor; -import org.apache.poi.xssf.usermodel.XSSFDataValidation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.*; -import java.lang.reflect.Field; -import java.math.BigDecimal; -import java.text.DecimalFormat; -import java.util.*; -import java.util.stream.Collectors; - -/** - * Excel鐩稿叧澶勭悊 - * - * @author ruoyi - */ -public class ExcelUtil<T> -{ - private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); - - /** - * Excel sheet鏈�澶ц鏁帮紝榛樿65536 - */ - public static final int sheetSize = 65536; - - /** - * 宸ヤ綔琛ㄥ悕绉� - */ - private String sheetName; - - /** - * 瀵煎嚭绫诲瀷锛圗XPORT:瀵煎嚭鏁版嵁锛汭MPORT锛氬鍏ユā鏉匡級 - */ - private Type type; - - /** - * 宸ヤ綔钖勫璞� - */ - private Workbook wb; - - /** - * 宸ヤ綔琛ㄥ璞� - */ - private Sheet sheet; - - /** - * 鏍峰紡鍒楄〃 - */ - private Map<String, CellStyle> styles; - - /** - * 瀵煎叆瀵煎嚭鏁版嵁鍒楄〃 - */ - private List<T> list; - - /** - * 娉ㄨВ鍒楄〃 - */ - private List<Object[]> fields; - - /** - * 鏈�澶ч珮搴� - */ - private short maxHeight; - - /** - * 缁熻鍒楄〃 - */ - private Map<Integer, Double> statistics = new HashMap<Integer, Double>(); - - /** - * 鏁板瓧鏍煎紡 - */ - private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); - - /** - * 瀹炰綋瀵硅薄 - */ - public Class<T> clazz; - - public ExcelUtil(Class<T> clazz) - { - this.clazz = clazz; - } - - public void init(List<T> list, String sheetName, Type type) - { - if (list == null) - { - list = new ArrayList<T>(); - } - this.list = list; - this.sheetName = sheetName; - this.type = type; - createExcelField(); - createWorkbook(); - } - - /** - * 瀵筫xcel琛ㄥ崟榛樿绗竴涓储寮曞悕杞崲鎴恖ist - * - * @param is 杈撳叆娴� - * @return 杞崲鍚庨泦鍚� - */ - public List<T> importExcel(InputStream is) throws Exception - { - return importExcel(StrUtil.EMPTY, is); - } - - /** - * 瀵筫xcel琛ㄥ崟鎸囧畾琛ㄦ牸绱㈠紩鍚嶈浆鎹㈡垚list - * - * @param sheetName 琛ㄦ牸绱㈠紩鍚� - * @param is 杈撳叆娴� - * @return 杞崲鍚庨泦鍚� - */ - public List<T> importExcel(String sheetName, InputStream is) throws Exception - { - this.type = Type.IMPORT; - this.wb = WorkbookFactory.create(is); - List<T> list = new ArrayList<T>(); - Sheet sheet = null; - if (Validator.isNotEmpty(sheetName)) - { - // 濡傛灉鎸囧畾sheet鍚�,鍒欏彇鎸囧畾sheet涓殑鍐呭. - sheet = wb.getSheet(sheetName); - } - else - { - // 濡傛灉浼犲叆鐨剆heet鍚嶄笉瀛樺湪鍒欓粯璁ゆ寚鍚戠1涓猻heet. - sheet = wb.getSheetAt(0); - } - - if (sheet == null) - { - throw new IOException("鏂囦欢sheet涓嶅瓨鍦�"); - } - - int rows = sheet.getPhysicalNumberOfRows(); - - if (rows > 0) - { - // 瀹氫箟涓�涓猰ap鐢ㄤ簬瀛樻斁excel鍒楃殑搴忓彿鍜宖ield. - Map<String, Integer> cellMap = new HashMap<String, Integer>(); - // 鑾峰彇琛ㄥご - Row heard = sheet.getRow(0); - for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) - { - Cell cell = heard.getCell(i); - if (Validator.isNotNull(cell)) - { - String value = this.getCellValue(heard, i).toString(); - cellMap.put(value, i); - } - else - { - cellMap.put(null, i); - } - } - // 鏈夋暟鎹椂鎵嶅鐞� 寰楀埌绫荤殑鎵�鏈塮ield. - Field[] allFields = clazz.getDeclaredFields(); - // 瀹氫箟涓�涓猰ap鐢ㄤ簬瀛樻斁鍒楃殑搴忓彿鍜宖ield. - Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>(); - for (int col = 0; col < allFields.length; col++) - { - Field field = allFields[col]; - Excel attr = field.getAnnotation(Excel.class); - if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) - { - // 璁剧疆绫荤殑绉佹湁瀛楁灞炴�у彲璁块棶. - field.setAccessible(true); - Integer column = cellMap.get(attr.name()); - if (column != null) - { - fieldsMap.put(column, field); - } - } - } - for (int i = 1; i < rows; i++) - { - // 浠庣2琛屽紑濮嬪彇鏁版嵁,榛樿绗竴琛屾槸琛ㄥご. - Row row = sheet.getRow(i); - if(row == null) - { - continue; - } - T entity = null; - for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet()) - { - Object val = this.getCellValue(row, entry.getKey()); - - // 濡傛灉涓嶅瓨鍦ㄥ疄渚嬪垯鏂板缓. - entity = (entity == null ? clazz.newInstance() : entity); - // 浠巑ap涓緱鍒板搴斿垪鐨刦ield. - Field field = fieldsMap.get(entry.getKey()); - // 鍙栧緱绫诲瀷,骞舵牴鎹璞$被鍨嬭缃��. - Class<?> fieldType = field.getType(); - if (String.class == fieldType) - { - String s = Convert.toStr(val); - if (StrUtil.endWith(s, ".0")) - { - val = StrUtil.subBefore(s, ".0",false); - } - else - { - String dateFormat = field.getAnnotation(Excel.class).dateFormat(); - if (Validator.isNotEmpty(dateFormat)) - { - val = DateUtils.parseDateToStr(dateFormat, (Date) val); - } - else - { - val = Convert.toStr(val); - } - } - } - else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && Validator.isNumber(Convert.toStr(val))) - { - val = Convert.toInt(val); - } - else if (Long.TYPE == fieldType || Long.class == fieldType) - { - val = Convert.toLong(val); - } - else if (Double.TYPE == fieldType || Double.class == fieldType) - { - val = Convert.toDouble(val); - } - else if (Float.TYPE == fieldType || Float.class == fieldType) - { - val = Convert.toFloat(val); - } - else if (BigDecimal.class == fieldType) - { - val = Convert.toBigDecimal(val); - } - else if (Date.class == fieldType) - { - if (val instanceof String) - { - val = DateUtils.parseDate(val); - } - else if (val instanceof Double) - { - val = DateUtil.getJavaDate((Double) val); - } - } - else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) - { - val = Convert.toBool(val, false); - } - if (Validator.isNotNull(fieldType)) - { - Excel attr = field.getAnnotation(Excel.class); - String propertyName = field.getName(); - if (Validator.isNotEmpty(attr.targetAttr())) - { - propertyName = field.getName() + "." + attr.targetAttr(); - } - else if (Validator.isNotEmpty(attr.readConverterExp())) - { - val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); - } - else if (Validator.isNotEmpty(attr.dictType())) - { - val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); - } - ReflectUtils.invokeSetter(entity, propertyName, val); - } - } - list.add(entity); - } - } - return list; - } - - /** - * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟 - * - * @param list 瀵煎嚭鏁版嵁闆嗗悎 - * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О - * @return 缁撴灉 - */ - public AjaxResult exportExcel(List<T> list, String sheetName) - { - this.init(list, sheetName, Type.EXPORT); - return exportExcel(); - } - - /** - * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟 - * - * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О - * @return 缁撴灉 - */ - public AjaxResult importTemplateExcel(String sheetName) - { - this.init(null, sheetName, Type.IMPORT); - return exportExcel(); - } - - /** - * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟 - * - * @return 缁撴灉 - */ - public AjaxResult exportExcel() - { - OutputStream out = null; - try - { - // 鍙栧嚭涓�鍏辨湁澶氬皯涓猻heet. - double sheetNo = Math.ceil(list.size() / sheetSize); - for (int index = 0; index <= sheetNo; index++) - { - createSheet(sheetNo, index); - - // 浜х敓涓�琛� - Row row = sheet.createRow(0); - int column = 0; - // 鍐欏叆鍚勪釜瀛楁鐨勫垪澶村悕绉� - for (Object[] os : fields) - { - Excel excel = (Excel) os[1]; - this.createCell(excel, row, column++); - } - if (Type.EXPORT.equals(type)) - { - fillExcelData(index, row); - addStatisticsRow(); - } - } - String filename = encodingFilename(sheetName); - out = new FileOutputStream(getAbsoluteFile(filename)); - wb.write(out); - return AjaxResult.success(filename); - } - catch (Exception e) - { - log.error("瀵煎嚭Excel寮傚父{}", e.getMessage()); - throw new CustomException("瀵煎嚭Excel澶辫触锛岃鑱旂郴缃戠珯绠$悊鍛橈紒"); - } - finally - { - if (wb != null) - { - try - { - wb.close(); - } - catch (IOException e1) - { - e1.printStackTrace(); - } - } - if (out != null) - { - try - { - out.close(); - } - catch (IOException e1) - { - e1.printStackTrace(); - } - } - } - } - - /** - * 濉厖excel鏁版嵁 - * - * @param index 搴忓彿 - * @param row 鍗曞厓鏍艰 - */ - public void fillExcelData(int index, Row row) - { - int startNo = index * sheetSize; - int endNo = Math.min(startNo + sheetSize, list.size()); - for (int i = startNo; i < endNo; i++) - { - row = sheet.createRow(i + 1 - startNo); - // 寰楀埌瀵煎嚭瀵硅薄. - T vo = (T) list.get(i); - int column = 0; - for (Object[] os : fields) - { - Field field = (Field) os[0]; - Excel excel = (Excel) os[1]; - // 璁剧疆瀹炰綋绫荤鏈夊睘鎬у彲璁块棶 - field.setAccessible(true); - this.addCell(excel, row, vo, field, column++); - } - } - } - - /** - * 鍒涘缓琛ㄦ牸鏍峰紡 - * - * @param wb 宸ヤ綔钖勫璞� - * @return 鏍峰紡鍒楄〃 - */ - private Map<String, CellStyle> createStyles(Workbook wb) - { - // 鍐欏叆鍚勬潯璁板綍,姣忔潯璁板綍瀵瑰簲excel琛ㄤ腑鐨勪竴琛� - Map<String, CellStyle> styles = new HashMap<String, CellStyle>(); - CellStyle style = wb.createCellStyle(); - style.setAlignment(HorizontalAlignment.CENTER); - style.setVerticalAlignment(VerticalAlignment.CENTER); - style.setBorderRight(BorderStyle.THIN); - style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderLeft(BorderStyle.THIN); - style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderTop(BorderStyle.THIN); - style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderBottom(BorderStyle.THIN); - style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - Font dataFont = wb.createFont(); - dataFont.setFontName("Arial"); - dataFont.setFontHeightInPoints((short) 10); - style.setFont(dataFont); - styles.put("data", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(HorizontalAlignment.CENTER); - style.setVerticalAlignment(VerticalAlignment.CENTER); - style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setFillPattern(FillPatternType.SOLID_FOREGROUND); - Font headerFont = wb.createFont(); - headerFont.setFontName("Arial"); - headerFont.setFontHeightInPoints((short) 10); - headerFont.setBold(true); - headerFont.setColor(IndexedColors.WHITE.getIndex()); - style.setFont(headerFont); - styles.put("header", style); - - style = wb.createCellStyle(); - style.setAlignment(HorizontalAlignment.CENTER); - style.setVerticalAlignment(VerticalAlignment.CENTER); - Font totalFont = wb.createFont(); - totalFont.setFontName("Arial"); - totalFont.setFontHeightInPoints((short) 10); - style.setFont(totalFont); - styles.put("total", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(HorizontalAlignment.LEFT); - styles.put("data1", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(HorizontalAlignment.CENTER); - styles.put("data2", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(HorizontalAlignment.RIGHT); - styles.put("data3", style); - - return styles; - } - - /** - * 鍒涘缓鍗曞厓鏍� - */ - public Cell createCell(Excel attr, Row row, int column) - { - // 鍒涘缓鍒� - Cell cell = row.createCell(column); - // 鍐欏叆鍒椾俊鎭� - cell.setCellValue(attr.name()); - setDataValidation(attr, row, column); - cell.setCellStyle(styles.get("header")); - return cell; - } - - /** - * 璁剧疆鍗曞厓鏍间俊鎭� - * - * @param value 鍗曞厓鏍煎�� - * @param attr 娉ㄨВ鐩稿叧 - * @param cell 鍗曞厓鏍间俊鎭� - */ - public void setCellVo(Object value, Excel attr, Cell cell) - { - if (ColumnType.STRING == attr.cellType()) - { - cell.setCellValue(Validator.isNull(value) ? attr.defaultValue() : value + attr.suffix()); - } - else if (ColumnType.NUMERIC == attr.cellType()) - { - if (Validator.isNotNull(value)) - { - cell.setCellValue(StrUtil.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); - } - } - else if (ColumnType.IMAGE == attr.cellType()) - { - ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), - cell.getRow().getRowNum() + 1); - String imagePath = Convert.toStr(value); - if (Validator.isNotEmpty(imagePath)) - { - byte[] data = ImageUtils.getImage(imagePath); - getDrawingPatriarch(cell.getSheet()).createPicture(anchor, - cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); - } - } - } - - /** - * 鑾峰彇鐢诲竷 - */ - public static Drawing<?> getDrawingPatriarch(Sheet sheet) - { - if (sheet.getDrawingPatriarch() == null) - { - sheet.createDrawingPatriarch(); - } - return sheet.getDrawingPatriarch(); - } - - /** - * 鑾峰彇鍥剧墖绫诲瀷,璁剧疆鍥剧墖鎻掑叆绫诲瀷 - */ - public int getImageType(byte[] value) - { - String type = FileTypeUtils.getFileExtendName(value); - if ("JPG".equalsIgnoreCase(type)) - { - return Workbook.PICTURE_TYPE_JPEG; - } - else if ("PNG".equalsIgnoreCase(type)) - { - return Workbook.PICTURE_TYPE_PNG; - } - return Workbook.PICTURE_TYPE_JPEG; - } - - /** - * 鍒涘缓琛ㄦ牸鏍峰紡 - */ - public void setDataValidation(Excel attr, Row row, int column) - { - if (attr.name().indexOf("娉細") >= 0) - { - sheet.setColumnWidth(column, 6000); - } - else - { - // 璁剧疆鍒楀 - sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); - } - // 濡傛灉璁剧疆浜嗘彁绀轰俊鎭垯榧犳爣鏀句笂鍘绘彁绀�. - if (Validator.isNotEmpty(attr.prompt())) - { - // 杩欓噷榛樿璁句簡2-101鍒楁彁绀�. - setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); - } - // 濡傛灉璁剧疆浜哻ombo灞炴�у垯鏈垪鍙兘閫夋嫨涓嶈兘杈撳叆 - if (attr.combo().length > 0) - { - // 杩欓噷榛樿璁句簡2-101鍒楀彧鑳介�夋嫨涓嶈兘杈撳叆. - setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); - } - } - - /** - * 娣诲姞鍗曞厓鏍� - */ - public Cell addCell(Excel attr, Row row, T vo, Field field, int column) - { - Cell cell = null; - try - { - // 璁剧疆琛岄珮 - row.setHeight(maxHeight); - // 鏍规嵁Excel涓缃儏鍐靛喅瀹氭槸鍚﹀鍑�,鏈変簺鎯呭喌闇�瑕佷繚鎸佷负绌�,甯屾湜鐢ㄦ埛濉啓杩欎竴鍒�. - if (attr.isExport()) - { - // 鍒涘缓cell - cell = row.createCell(column); - int align = attr.align().value(); - cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : ""))); - - // 鐢ㄤ簬璇诲彇瀵硅薄涓殑灞炴�� - Object value = getTargetValue(vo, field, attr); - String dateFormat = attr.dateFormat(); - String readConverterExp = attr.readConverterExp(); - String separator = attr.separator(); - String dictType = attr.dictType(); - if (Validator.isNotEmpty(dateFormat) && Validator.isNotNull(value)) - { - cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); - } - else if (Validator.isNotEmpty(readConverterExp) && Validator.isNotNull(value)) - { - cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); - } - else if (Validator.isNotEmpty(dictType) && Validator.isNotNull(value)) - { - cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator)); - } - else if (value instanceof BigDecimal && -1 != attr.scale()) - { - cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString()); - } - else - { - // 璁剧疆鍒楃被鍨� - setCellVo(value, attr, cell); - } - addStatisticsData(column, Convert.toStr(value), attr); - } - } - catch (Exception e) - { - log.error("瀵煎嚭Excel澶辫触{}", e); - } - return cell; - } - - /** - * 璁剧疆 POI XSSFSheet 鍗曞厓鏍兼彁绀� - * - * @param sheet 琛ㄥ崟 - * @param promptTitle 鎻愮ず鏍囬 - * @param promptContent 鎻愮ず鍐呭 - * @param firstRow 寮�濮嬭 - * @param endRow 缁撴潫琛� - * @param firstCol 寮�濮嬪垪 - * @param endCol 缁撴潫鍒� - */ - public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, - int firstCol, int endCol) - { - DataValidationHelper helper = sheet.getDataValidationHelper(); - DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); - CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); - DataValidation dataValidation = helper.createValidation(constraint, regions); - dataValidation.createPromptBox(promptTitle, promptContent); - dataValidation.setShowPromptBox(true); - sheet.addValidationData(dataValidation); - } - - /** - * 璁剧疆鏌愪簺鍒楃殑鍊煎彧鑳借緭鍏ラ鍒剁殑鏁版嵁,鏄剧ず涓嬫媺妗�. - * - * @param sheet 瑕佽缃殑sheet. - * @param textlist 涓嬫媺妗嗘樉绀虹殑鍐呭 - * @param firstRow 寮�濮嬭 - * @param endRow 缁撴潫琛� - * @param firstCol 寮�濮嬪垪 - * @param endCol 缁撴潫鍒� - * @return 璁剧疆濂界殑sheet. - */ - public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) - { - DataValidationHelper helper = sheet.getDataValidationHelper(); - // 鍔犺浇涓嬫媺鍒楄〃鍐呭 - DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); - // 璁剧疆鏁版嵁鏈夋晥鎬у姞杞藉湪鍝釜鍗曞厓鏍间笂,鍥涗釜鍙傛暟鍒嗗埆鏄細璧峰琛屻�佺粓姝㈣銆佽捣濮嬪垪銆佺粓姝㈠垪 - CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); - // 鏁版嵁鏈夋晥鎬у璞� - DataValidation dataValidation = helper.createValidation(constraint, regions); - // 澶勭悊Excel鍏煎鎬ч棶棰� - if (dataValidation instanceof XSSFDataValidation) - { - dataValidation.setSuppressDropDownArrow(true); - dataValidation.setShowErrorBox(true); - } - else - { - dataValidation.setSuppressDropDownArrow(false); - } - - sheet.addValidationData(dataValidation); - } - - /** - * 瑙f瀽瀵煎嚭鍊� 0=鐢�,1=濂�,2=鏈煡 - * - * @param propertyValue 鍙傛暟鍊� - * @param converterExp 缈昏瘧娉ㄨВ - * @param separator 鍒嗛殧绗� - * @return 瑙f瀽鍚庡�� - */ - public static String convertByExp(String propertyValue, String converterExp, String separator) - { - StringBuilder propertyString = new StringBuilder(); - String[] convertSource = converterExp.split(","); - for (String item : convertSource) - { - String[] itemArray = item.split("="); - if (StrUtil.containsAny(separator, propertyValue)) - { - for (String value : propertyValue.split(separator)) - { - if (itemArray[0].equals(value)) - { - propertyString.append(itemArray[1] + separator); - break; - } - } - } - else - { - if (itemArray[0].equals(propertyValue)) - { - return itemArray[1]; - } - } - } - return StrUtil.strip(propertyString.toString(), null,separator); - } - - /** - * 鍙嶅悜瑙f瀽鍊� 鐢�=0,濂�=1,鏈煡=2 - * - * @param propertyValue 鍙傛暟鍊� - * @param converterExp 缈昏瘧娉ㄨВ - * @param separator 鍒嗛殧绗� - * @return 瑙f瀽鍚庡�� - */ - public static String reverseByExp(String propertyValue, String converterExp, String separator) - { - StringBuilder propertyString = new StringBuilder(); - String[] convertSource = converterExp.split(","); - for (String item : convertSource) - { - String[] itemArray = item.split("="); - if (StrUtil.containsAny(separator, propertyValue)) - { - for (String value : propertyValue.split(separator)) - { - if (itemArray[1].equals(value)) - { - propertyString.append(itemArray[0] + separator); - break; - } - } - } - else - { - if (itemArray[1].equals(propertyValue)) - { - return itemArray[0]; - } - } - } - return StrUtil.strip(propertyString.toString(), null,separator); - } - - /** - * 瑙f瀽瀛楀吀鍊� - * - * @param dictValue 瀛楀吀鍊� - * @param dictType 瀛楀吀绫诲瀷 - * @param separator 鍒嗛殧绗� - * @return 瀛楀吀鏍囩 - */ - public static String convertDictByExp(String dictValue, String dictType, String separator) - { - return DictUtils.getDictLabel(dictType, dictValue, separator); - } - - /** - * 鍙嶅悜瑙f瀽鍊煎瓧鍏稿�� - * - * @param dictLabel 瀛楀吀鏍囩 - * @param dictType 瀛楀吀绫诲瀷 - * @param separator 鍒嗛殧绗� - * @return 瀛楀吀鍊� - */ - public static String reverseDictByExp(String dictLabel, String dictType, String separator) - { - return DictUtils.getDictValue(dictType, dictLabel, separator); - } - - /** - * 鍚堣缁熻淇℃伅 - */ - private void addStatisticsData(Integer index, String text, Excel entity) - { - if (entity != null && entity.isStatistics()) - { - Double temp = 0D; - if (!statistics.containsKey(index)) - { - statistics.put(index, temp); - } - try - { - temp = Double.valueOf(text); - } - catch (NumberFormatException e) - { - } - statistics.put(index, statistics.get(index) + temp); - } - } - - /** - * 鍒涘缓缁熻琛� - */ - public void addStatisticsRow() - { - if (statistics.size() > 0) - { - Cell cell = null; - Row row = sheet.createRow(sheet.getLastRowNum() + 1); - Set<Integer> keys = statistics.keySet(); - cell = row.createCell(0); - cell.setCellStyle(styles.get("total")); - cell.setCellValue("鍚堣"); - - for (Integer key : keys) - { - cell = row.createCell(key); - cell.setCellStyle(styles.get("total")); - cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); - } - statistics.clear(); - } - } - - /** - * 缂栫爜鏂囦欢鍚� - */ - public String encodingFilename(String filename) - { - filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; - return filename; - } - - /** - * 鑾峰彇涓嬭浇璺緞 - * - * @param filename 鏂囦欢鍚嶇О - */ - public String getAbsoluteFile(String filename) - { - String downloadPath = RuoYiConfig.getDownloadPath() + filename; - File desc = new File(downloadPath); - if (!desc.getParentFile().exists()) - { - desc.getParentFile().mkdirs(); - } - return downloadPath; - } - - /** - * 鑾峰彇bean涓殑灞炴�у�� - * - * @param vo 瀹炰綋瀵硅薄 - * @param field 瀛楁 - * @param excel 娉ㄨВ - * @return 鏈�缁堢殑灞炴�у�� - * @throws Exception - */ - private Object getTargetValue(T vo, Field field, Excel excel) throws Exception - { - Object o = field.get(vo); - if (Validator.isNotEmpty(excel.targetAttr())) - { - String target = excel.targetAttr(); - if (target.contains(".")) - { - String[] targets = target.split("[.]"); - for (String name : targets) - { - o = getValue(o, name); - } - } - else - { - o = getValue(o, target); - } - } - return o; - } - - /** - * 浠ョ被鐨勫睘鎬х殑get鏂规硶鏂规硶褰㈠紡鑾峰彇鍊� - * - * @param o - * @param name - * @return value - * @throws Exception - */ - private Object getValue(Object o, String name) throws Exception - { - if (Validator.isNotNull(o) && Validator.isNotEmpty(name)) - { - Class<?> clazz = o.getClass(); - Field field = clazz.getDeclaredField(name); - field.setAccessible(true); - o = field.get(o); - } - return o; - } - - /** - * 寰楀埌鎵�鏈夊畾涔夊瓧娈� - */ - private void createExcelField() - { - this.fields = new ArrayList<Object[]>(); - List<Field> tempFields = new ArrayList<>(); - tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); - tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); - for (Field field : tempFields) - { - // 鍗曟敞瑙� - if (field.isAnnotationPresent(Excel.class)) - { - putToField(field, field.getAnnotation(Excel.class)); - } - - // 澶氭敞瑙� - if (field.isAnnotationPresent(Excels.class)) - { - Excels attrs = field.getAnnotation(Excels.class); - Excel[] excels = attrs.value(); - for (Excel excel : excels) - { - putToField(field, excel); - } - } - } - this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); - this.maxHeight = getRowHeight(); - } - - /** - * 鏍规嵁娉ㄨВ鑾峰彇鏈�澶ц楂� - */ - public short getRowHeight() - { - double maxHeight = 0; - for (Object[] os : this.fields) - { - Excel excel = (Excel) os[1]; - maxHeight = maxHeight > excel.height() ? maxHeight : excel.height(); - } - return (short) (maxHeight * 20); - } - - /** - * 鏀惧埌瀛楁闆嗗悎涓� - */ - private void putToField(Field field, Excel attr) - { - if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) - { - this.fields.add(new Object[] { field, attr }); - } - } - - /** - * 鍒涘缓涓�涓伐浣滅翱 - */ - public void createWorkbook() - { - this.wb = new SXSSFWorkbook(500); - } - - /** - * 鍒涘缓宸ヤ綔琛� - * - * @param sheetNo sheet鏁伴噺 - * @param index 搴忓彿 - */ - public void createSheet(double sheetNo, int index) - { - this.sheet = wb.createSheet(); - this.styles = createStyles(wb); - // 璁剧疆宸ヤ綔琛ㄧ殑鍚嶇О. - if (sheetNo == 0) - { - wb.setSheetName(index, sheetName); - } - else - { - wb.setSheetName(index, sheetName + index); - } - } - - /** - * 鑾峰彇鍗曞厓鏍煎�� - * - * @param row 鑾峰彇鐨勮 - * @param column 鑾峰彇鍗曞厓鏍煎垪鍙� - * @return 鍗曞厓鏍煎�� - */ - public Object getCellValue(Row row, int column) - { - if (row == null) - { - return row; - } - Object val = ""; - try - { - Cell cell = row.getCell(column); - if (Validator.isNotNull(cell)) - { - if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) - { - val = cell.getNumericCellValue(); - if (DateUtil.isCellDateFormatted(cell)) - { - val = DateUtil.getJavaDate((Double) val); // POI Excel 鏃ユ湡鏍煎紡杞崲 - } - else - { - if ((Double) val % 1 != 0) - { - val = new BigDecimal(val.toString()); - } - else - { - val = new DecimalFormat("0").format(val); - } - } - } - else if (cell.getCellType() == CellType.STRING) - { - val = cell.getStringCellValue(); - } - else if (cell.getCellType() == CellType.BOOLEAN) - { - val = cell.getBooleanCellValue(); - } - else if (cell.getCellType() == CellType.ERROR) - { - val = cell.getErrorCellValue(); - } - - } - } - catch (Exception e) - { - return val; - } - return val; - } -} \ No newline at end of file +package com.ruoyi.common.utils.poi; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.annotation.Excel.ColumnType; +import com.ruoyi.common.annotation.Excel.Type; +import com.ruoyi.common.annotation.Excels; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.exception.CustomException; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.DictUtils; +import com.ruoyi.common.utils.file.FileTypeUtils; +import com.ruoyi.common.utils.file.ImageUtils; +import com.ruoyi.common.utils.reflect.ReflectUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Excel鐩稿叧澶勭悊 + * + * @author ruoyi + */ +public class ExcelUtil<T> +{ + private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); + + /** + * Excel sheet鏈�澶ц鏁帮紝榛樿65536 + */ + public static final int sheetSize = 65536; + + /** + * 宸ヤ綔琛ㄥ悕绉� + */ + private String sheetName; + + /** + * 瀵煎嚭绫诲瀷锛圗XPORT:瀵煎嚭鏁版嵁锛汭MPORT锛氬鍏ユā鏉匡級 + */ + private Type type; + + /** + * 宸ヤ綔钖勫璞� + */ + private Workbook wb; + + /** + * 宸ヤ綔琛ㄥ璞� + */ + private Sheet sheet; + + /** + * 鏍峰紡鍒楄〃 + */ + private Map<String, CellStyle> styles; + + /** + * 瀵煎叆瀵煎嚭鏁版嵁鍒楄〃 + */ + private List<T> list; + + /** + * 娉ㄨВ鍒楄〃 + */ + private List<Object[]> fields; + + /** + * 鏈�澶ч珮搴� + */ + private short maxHeight; + + /** + * 缁熻鍒楄〃 + */ + private Map<Integer, Double> statistics = new HashMap<Integer, Double>(); + + /** + * 鏁板瓧鏍煎紡 + */ + private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); + + /** + * 瀹炰綋瀵硅薄 + */ + public Class<T> clazz; + + public ExcelUtil(Class<T> clazz) + { + this.clazz = clazz; + } + + public void init(List<T> list, String sheetName, Type type) + { + if (list == null) + { + list = new ArrayList<T>(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + createExcelField(); + createWorkbook(); + } + + /** + * 瀵筫xcel琛ㄥ崟榛樿绗竴涓储寮曞悕杞崲鎴恖ist + * + * @param is 杈撳叆娴� + * @return 杞崲鍚庨泦鍚� + */ + public List<T> importExcel(InputStream is) throws Exception + { + return importExcel(StrUtil.EMPTY, is); + } + + /** + * 瀵筫xcel琛ㄥ崟鎸囧畾琛ㄦ牸绱㈠紩鍚嶈浆鎹㈡垚list + * + * @param sheetName 琛ㄦ牸绱㈠紩鍚� + * @param is 杈撳叆娴� + * @return 杞崲鍚庨泦鍚� + */ + public List<T> importExcel(String sheetName, InputStream is) throws Exception + { + this.type = Type.IMPORT; + this.wb = WorkbookFactory.create(is); + List<T> list = new ArrayList<T>(); + Sheet sheet = null; + if (Validator.isNotEmpty(sheetName)) + { + // 濡傛灉鎸囧畾sheet鍚�,鍒欏彇鎸囧畾sheet涓殑鍐呭. + sheet = wb.getSheet(sheetName); + } + else + { + // 濡傛灉浼犲叆鐨剆heet鍚嶄笉瀛樺湪鍒欓粯璁ゆ寚鍚戠1涓猻heet. + sheet = wb.getSheetAt(0); + } + + if (sheet == null) + { + throw new IOException("鏂囦欢sheet涓嶅瓨鍦�"); + } + + int rows = sheet.getPhysicalNumberOfRows(); + + if (rows > 0) + { + // 瀹氫箟涓�涓猰ap鐢ㄤ簬瀛樻斁excel鍒楃殑搴忓彿鍜宖ield. + Map<String, Integer> cellMap = new HashMap<String, Integer>(); + // 鑾峰彇琛ㄥご + Row heard = sheet.getRow(0); + for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) + { + Cell cell = heard.getCell(i); + if (Validator.isNotNull(cell)) + { + String value = this.getCellValue(heard, i).toString(); + cellMap.put(value, i); + } + else + { + cellMap.put(null, i); + } + } + // 鏈夋暟鎹椂鎵嶅鐞� 寰楀埌绫荤殑鎵�鏈塮ield. + Field[] allFields = clazz.getDeclaredFields(); + // 瀹氫箟涓�涓猰ap鐢ㄤ簬瀛樻斁鍒楃殑搴忓彿鍜宖ield. + Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>(); + for (int col = 0; col < allFields.length; col++) + { + Field field = allFields[col]; + Excel attr = field.getAnnotation(Excel.class); + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) + { + // 璁剧疆绫荤殑绉佹湁瀛楁灞炴�у彲璁块棶. + field.setAccessible(true); + Integer column = cellMap.get(attr.name()); + if (column != null) + { + fieldsMap.put(column, field); + } + } + } + for (int i = 1; i < rows; i++) + { + // 浠庣2琛屽紑濮嬪彇鏁版嵁,榛樿绗竴琛屾槸琛ㄥご. + Row row = sheet.getRow(i); + if(row == null) + { + continue; + } + T entity = null; + for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet()) + { + Object val = this.getCellValue(row, entry.getKey()); + + // 濡傛灉涓嶅瓨鍦ㄥ疄渚嬪垯鏂板缓. + entity = (entity == null ? clazz.newInstance() : entity); + // 浠巑ap涓緱鍒板搴斿垪鐨刦ield. + Field field = fieldsMap.get(entry.getKey()); + // 鍙栧緱绫诲瀷,骞舵牴鎹璞$被鍨嬭缃��. + Class<?> fieldType = field.getType(); + if (String.class == fieldType) + { + String s = Convert.toStr(val); + if (StrUtil.endWith(s, ".0")) + { + val = StrUtil.subBefore(s, ".0",false); + } + else + { + String dateFormat = field.getAnnotation(Excel.class).dateFormat(); + if (Validator.isNotEmpty(dateFormat)) + { + val = DateUtils.parseDateToStr(dateFormat, (Date) val); + } + else + { + val = Convert.toStr(val); + } + } + } + else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && Validator.isNumber(Convert.toStr(val))) + { + val = Convert.toInt(val); + } + else if (Long.TYPE == fieldType || Long.class == fieldType) + { + val = Convert.toLong(val); + } + else if (Double.TYPE == fieldType || Double.class == fieldType) + { + val = Convert.toDouble(val); + } + else if (Float.TYPE == fieldType || Float.class == fieldType) + { + val = Convert.toFloat(val); + } + else if (BigDecimal.class == fieldType) + { + val = Convert.toBigDecimal(val); + } + else if (Date.class == fieldType) + { + if (val instanceof String) + { + val = DateUtils.parseDate(val); + } + else if (val instanceof Double) + { + val = DateUtil.getJavaDate((Double) val); + } + } + else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) + { + val = Convert.toBool(val, false); + } + if (Validator.isNotNull(fieldType)) + { + Excel attr = field.getAnnotation(Excel.class); + String propertyName = field.getName(); + if (Validator.isNotEmpty(attr.targetAttr())) + { + propertyName = field.getName() + "." + attr.targetAttr(); + } + else if (Validator.isNotEmpty(attr.readConverterExp())) + { + val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); + } + else if (Validator.isNotEmpty(attr.dictType())) + { + val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); + } + ReflectUtils.invokeSetter(entity, propertyName, val); + } + } + list.add(entity); + } + } + return list; + } + + /** + * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟 + * + * @param list 瀵煎嚭鏁版嵁闆嗗悎 + * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О + * @return 缁撴灉 + */ + public AjaxResult exportExcel(List<T> list, String sheetName) + { + this.init(list, sheetName, Type.EXPORT); + return exportExcel(); + } + + /** + * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟 + * + * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О + * @return 缁撴灉 + */ + public AjaxResult importTemplateExcel(String sheetName) + { + this.init(null, sheetName, Type.IMPORT); + return exportExcel(); + } + + /** + * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟 + * + * @return 缁撴灉 + */ + public AjaxResult exportExcel() + { + OutputStream out = null; + try + { + // 鍙栧嚭涓�鍏辨湁澶氬皯涓猻heet. + double sheetNo = Math.ceil(list.size() / sheetSize); + for (int index = 0; index <= sheetNo; index++) + { + createSheet(sheetNo, index); + + // 浜х敓涓�琛� + Row row = sheet.createRow(0); + int column = 0; + // 鍐欏叆鍚勪釜瀛楁鐨勫垪澶村悕绉� + for (Object[] os : fields) + { + Excel excel = (Excel) os[1]; + this.createCell(excel, row, column++); + } + if (Type.EXPORT.equals(type)) + { + fillExcelData(index, row); + addStatisticsRow(); + } + } + String filename = encodingFilename(sheetName); + out = new FileOutputStream(getAbsoluteFile(filename)); + wb.write(out); + return AjaxResult.success(filename); + } + catch (Exception e) + { + log.error("瀵煎嚭Excel寮傚父{}", e.getMessage()); + throw new CustomException("瀵煎嚭Excel澶辫触锛岃鑱旂郴缃戠珯绠$悊鍛橈紒"); + } + finally + { + if (wb != null) + { + try + { + wb.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + if (out != null) + { + try + { + out.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + } + } + + /** + * 濉厖excel鏁版嵁 + * + * @param index 搴忓彿 + * @param row 鍗曞厓鏍艰 + */ + public void fillExcelData(int index, Row row) + { + int startNo = index * sheetSize; + int endNo = Math.min(startNo + sheetSize, list.size()); + for (int i = startNo; i < endNo; i++) + { + row = sheet.createRow(i + 1 - startNo); + // 寰楀埌瀵煎嚭瀵硅薄. + T vo = (T) list.get(i); + int column = 0; + for (Object[] os : fields) + { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + // 璁剧疆瀹炰綋绫荤鏈夊睘鎬у彲璁块棶 + field.setAccessible(true); + this.addCell(excel, row, vo, field, column++); + } + } + } + + /** + * 鍒涘缓琛ㄦ牸鏍峰紡 + * + * @param wb 宸ヤ綔钖勫璞� + * @return 鏍峰紡鍒楄〃 + */ + private Map<String, CellStyle> createStyles(Workbook wb) + { + // 鍐欏叆鍚勬潯璁板綍,姣忔潯璁板綍瀵瑰簲excel琛ㄤ腑鐨勪竴琛� + Map<String, CellStyle> styles = new HashMap<String, CellStyle>(); + CellStyle style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBold(true); + headerFont.setColor(IndexedColors.WHITE.getIndex()); + style.setFont(headerFont); + styles.put("header", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font totalFont = wb.createFont(); + totalFont.setFontName("Arial"); + totalFont.setFontHeightInPoints((short) 10); + style.setFont(totalFont); + styles.put("total", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.LEFT); + styles.put("data1", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + styles.put("data2", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.RIGHT); + styles.put("data3", style); + + return styles; + } + + /** + * 鍒涘缓鍗曞厓鏍� + */ + public Cell createCell(Excel attr, Row row, int column) + { + // 鍒涘缓鍒� + Cell cell = row.createCell(column); + // 鍐欏叆鍒椾俊鎭� + cell.setCellValue(attr.name()); + setDataValidation(attr, row, column); + cell.setCellStyle(styles.get("header")); + return cell; + } + + /** + * 璁剧疆鍗曞厓鏍间俊鎭� + * + * @param value 鍗曞厓鏍煎�� + * @param attr 娉ㄨВ鐩稿叧 + * @param cell 鍗曞厓鏍间俊鎭� + */ + public void setCellVo(Object value, Excel attr, Cell cell) + { + if (ColumnType.STRING == attr.cellType()) + { + cell.setCellValue(Validator.isNull(value) ? attr.defaultValue() : value + attr.suffix()); + } + else if (ColumnType.NUMERIC == attr.cellType()) + { + if (Validator.isNotNull(value)) + { + cell.setCellValue(StrUtil.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); + } + } + else if (ColumnType.IMAGE == attr.cellType()) + { + ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), + cell.getRow().getRowNum() + 1); + String imagePath = Convert.toStr(value); + if (Validator.isNotEmpty(imagePath)) + { + byte[] data = ImageUtils.getImage(imagePath); + getDrawingPatriarch(cell.getSheet()).createPicture(anchor, + cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); + } + } + } + + /** + * 鑾峰彇鐢诲竷 + */ + public static Drawing<?> getDrawingPatriarch(Sheet sheet) + { + if (sheet.getDrawingPatriarch() == null) + { + sheet.createDrawingPatriarch(); + } + return sheet.getDrawingPatriarch(); + } + + /** + * 鑾峰彇鍥剧墖绫诲瀷,璁剧疆鍥剧墖鎻掑叆绫诲瀷 + */ + public int getImageType(byte[] value) + { + String type = FileTypeUtils.getFileExtendName(value); + if ("JPG".equalsIgnoreCase(type)) + { + return Workbook.PICTURE_TYPE_JPEG; + } + else if ("PNG".equalsIgnoreCase(type)) + { + return Workbook.PICTURE_TYPE_PNG; + } + return Workbook.PICTURE_TYPE_JPEG; + } + + /** + * 鍒涘缓琛ㄦ牸鏍峰紡 + */ + public void setDataValidation(Excel attr, Row row, int column) + { + if (attr.name().indexOf("娉細") >= 0) + { + sheet.setColumnWidth(column, 6000); + } + else + { + // 璁剧疆鍒楀 + sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); + } + // 濡傛灉璁剧疆浜嗘彁绀轰俊鎭垯榧犳爣鏀句笂鍘绘彁绀�. + if (Validator.isNotEmpty(attr.prompt())) + { + // 杩欓噷榛樿璁句簡2-101鍒楁彁绀�. + setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); + } + // 濡傛灉璁剧疆浜哻ombo灞炴�у垯鏈垪鍙兘閫夋嫨涓嶈兘杈撳叆 + if (attr.combo().length > 0) + { + // 杩欓噷榛樿璁句簡2-101鍒楀彧鑳介�夋嫨涓嶈兘杈撳叆. + setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); + } + } + + /** + * 娣诲姞鍗曞厓鏍� + */ + public Cell addCell(Excel attr, Row row, T vo, Field field, int column) + { + Cell cell = null; + try + { + // 璁剧疆琛岄珮 + row.setHeight(maxHeight); + // 鏍规嵁Excel涓缃儏鍐靛喅瀹氭槸鍚﹀鍑�,鏈変簺鎯呭喌闇�瑕佷繚鎸佷负绌�,甯屾湜鐢ㄦ埛濉啓杩欎竴鍒�. + if (attr.isExport()) + { + // 鍒涘缓cell + cell = row.createCell(column); + int align = attr.align().value(); + cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : ""))); + + // 鐢ㄤ簬璇诲彇瀵硅薄涓殑灞炴�� + Object value = getTargetValue(vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + String separator = attr.separator(); + String dictType = attr.dictType(); + if (Validator.isNotEmpty(dateFormat) && Validator.isNotNull(value)) + { + cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); + } + else if (Validator.isNotEmpty(readConverterExp) && Validator.isNotNull(value)) + { + cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); + } + else if (Validator.isNotEmpty(dictType) && Validator.isNotNull(value)) + { + cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator)); + } + else if (value instanceof BigDecimal && -1 != attr.scale()) + { + cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString()); + } + else + { + // 璁剧疆鍒楃被鍨� + setCellVo(value, attr, cell); + } + addStatisticsData(column, Convert.toStr(value), attr); + } + } + catch (Exception e) + { + log.error("瀵煎嚭Excel澶辫触{}", e); + } + return cell; + } + + /** + * 璁剧疆 POI XSSFSheet 鍗曞厓鏍兼彁绀� + * + * @param sheet 琛ㄥ崟 + * @param promptTitle 鎻愮ず鏍囬 + * @param promptContent 鎻愮ず鍐呭 + * @param firstRow 寮�濮嬭 + * @param endRow 缁撴潫琛� + * @param firstCol 寮�濮嬪垪 + * @param endCol 缁撴潫鍒� + */ + public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, + int firstCol, int endCol) + { + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + DataValidation dataValidation = helper.createValidation(constraint, regions); + dataValidation.createPromptBox(promptTitle, promptContent); + dataValidation.setShowPromptBox(true); + sheet.addValidationData(dataValidation); + } + + /** + * 璁剧疆鏌愪簺鍒楃殑鍊煎彧鑳借緭鍏ラ鍒剁殑鏁版嵁,鏄剧ず涓嬫媺妗�. + * + * @param sheet 瑕佽缃殑sheet. + * @param textlist 涓嬫媺妗嗘樉绀虹殑鍐呭 + * @param firstRow 寮�濮嬭 + * @param endRow 缁撴潫琛� + * @param firstCol 寮�濮嬪垪 + * @param endCol 缁撴潫鍒� + * @return 璁剧疆濂界殑sheet. + */ + public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) + { + DataValidationHelper helper = sheet.getDataValidationHelper(); + // 鍔犺浇涓嬫媺鍒楄〃鍐呭 + DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); + // 璁剧疆鏁版嵁鏈夋晥鎬у姞杞藉湪鍝釜鍗曞厓鏍间笂,鍥涗釜鍙傛暟鍒嗗埆鏄細璧峰琛屻�佺粓姝㈣銆佽捣濮嬪垪銆佺粓姝㈠垪 + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + // 鏁版嵁鏈夋晥鎬у璞� + DataValidation dataValidation = helper.createValidation(constraint, regions); + // 澶勭悊Excel鍏煎鎬ч棶棰� + if (dataValidation instanceof XSSFDataValidation) + { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } + else + { + dataValidation.setSuppressDropDownArrow(false); + } + + sheet.addValidationData(dataValidation); + } + + /** + * 瑙f瀽瀵煎嚭鍊� 0=鐢�,1=濂�,2=鏈煡 + * + * @param propertyValue 鍙傛暟鍊� + * @param converterExp 缈昏瘧娉ㄨВ + * @param separator 鍒嗛殧绗� + * @return 瑙f瀽鍚庡�� + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) + { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) + { + String[] itemArray = item.split("="); + if (StrUtil.containsAny(propertyValue, separator)) + { + for (String value : propertyValue.split(separator)) + { + if (itemArray[0].equals(value)) + { + propertyString.append(itemArray[1] + separator); + break; + } + } + } + else + { + if (itemArray[0].equals(propertyValue)) + { + return itemArray[1]; + } + } + } + return StrUtil.strip(propertyString.toString(), null,separator); + } + + /** + * 鍙嶅悜瑙f瀽鍊� 鐢�=0,濂�=1,鏈煡=2 + * + * @param propertyValue 鍙傛暟鍊� + * @param converterExp 缈昏瘧娉ㄨВ + * @param separator 鍒嗛殧绗� + * @return 瑙f瀽鍚庡�� + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) + { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) + { + String[] itemArray = item.split("="); + if (StrUtil.containsAny(propertyValue, separator)) + { + for (String value : propertyValue.split(separator)) + { + if (itemArray[1].equals(value)) + { + propertyString.append(itemArray[0] + separator); + break; + } + } + } + else + { + if (itemArray[1].equals(propertyValue)) + { + return itemArray[0]; + } + } + } + return StrUtil.strip(propertyString.toString(), null,separator); + } + + /** + * 瑙f瀽瀛楀吀鍊� + * + * @param dictValue 瀛楀吀鍊� + * @param dictType 瀛楀吀绫诲瀷 + * @param separator 鍒嗛殧绗� + * @return 瀛楀吀鏍囩 + */ + public static String convertDictByExp(String dictValue, String dictType, String separator) + { + return DictUtils.getDictLabel(dictType, dictValue, separator); + } + + /** + * 鍙嶅悜瑙f瀽鍊煎瓧鍏稿�� + * + * @param dictLabel 瀛楀吀鏍囩 + * @param dictType 瀛楀吀绫诲瀷 + * @param separator 鍒嗛殧绗� + * @return 瀛楀吀鍊� + */ + public static String reverseDictByExp(String dictLabel, String dictType, String separator) + { + return DictUtils.getDictValue(dictType, dictLabel, separator); + } + + /** + * 鍚堣缁熻淇℃伅 + */ + private void addStatisticsData(Integer index, String text, Excel entity) + { + if (entity != null && entity.isStatistics()) + { + Double temp = 0D; + if (!statistics.containsKey(index)) + { + statistics.put(index, temp); + } + try + { + temp = Double.valueOf(text); + } + catch (NumberFormatException e) + { + } + statistics.put(index, statistics.get(index) + temp); + } + } + + /** + * 鍒涘缓缁熻琛� + */ + public void addStatisticsRow() + { + if (statistics.size() > 0) + { + Cell cell = null; + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + Set<Integer> keys = statistics.keySet(); + cell = row.createCell(0); + cell.setCellStyle(styles.get("total")); + cell.setCellValue("鍚堣"); + + for (Integer key : keys) + { + cell = row.createCell(key); + cell.setCellStyle(styles.get("total")); + cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); + } + statistics.clear(); + } + } + + /** + * 缂栫爜鏂囦欢鍚� + */ + public String encodingFilename(String filename) + { + filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; + return filename; + } + + /** + * 鑾峰彇涓嬭浇璺緞 + * + * @param filename 鏂囦欢鍚嶇О + */ + public String getAbsoluteFile(String filename) + { + String downloadPath = RuoYiConfig.getDownloadPath() + filename; + File desc = new File(downloadPath); + if (!desc.getParentFile().exists()) + { + desc.getParentFile().mkdirs(); + } + return downloadPath; + } + + /** + * 鑾峰彇bean涓殑灞炴�у�� + * + * @param vo 瀹炰綋瀵硅薄 + * @param field 瀛楁 + * @param excel 娉ㄨВ + * @return 鏈�缁堢殑灞炴�у�� + * @throws Exception + */ + private Object getTargetValue(T vo, Field field, Excel excel) throws Exception + { + Object o = field.get(vo); + if (Validator.isNotEmpty(excel.targetAttr())) + { + String target = excel.targetAttr(); + if (target.contains(".")) + { + String[] targets = target.split("[.]"); + for (String name : targets) + { + o = getValue(o, name); + } + } + else + { + o = getValue(o, target); + } + } + return o; + } + + /** + * 浠ョ被鐨勫睘鎬х殑get鏂规硶鏂规硶褰㈠紡鑾峰彇鍊� + * + * @param o + * @param name + * @return value + * @throws Exception + */ + private Object getValue(Object o, String name) throws Exception + { + if (Validator.isNotNull(o) && Validator.isNotEmpty(name)) + { + Class<?> clazz = o.getClass(); + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + o = field.get(o); + } + return o; + } + + /** + * 寰楀埌鎵�鏈夊畾涔夊瓧娈� + */ + private void createExcelField() + { + this.fields = new ArrayList<Object[]>(); + List<Field> tempFields = new ArrayList<>(); + tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); + tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); + for (Field field : tempFields) + { + // 鍗曟敞瑙� + if (field.isAnnotationPresent(Excel.class)) + { + putToField(field, field.getAnnotation(Excel.class)); + } + + // 澶氭敞瑙� + if (field.isAnnotationPresent(Excels.class)) + { + Excels attrs = field.getAnnotation(Excels.class); + Excel[] excels = attrs.value(); + for (Excel excel : excels) + { + putToField(field, excel); + } + } + } + this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); + this.maxHeight = getRowHeight(); + } + + /** + * 鏍规嵁娉ㄨВ鑾峰彇鏈�澶ц楂� + */ + public short getRowHeight() + { + double maxHeight = 0; + for (Object[] os : this.fields) + { + Excel excel = (Excel) os[1]; + maxHeight = maxHeight > excel.height() ? maxHeight : excel.height(); + } + return (short) (maxHeight * 20); + } + + /** + * 鏀惧埌瀛楁闆嗗悎涓� + */ + private void putToField(Field field, Excel attr) + { + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) + { + this.fields.add(new Object[] { field, attr }); + } + } + + /** + * 鍒涘缓涓�涓伐浣滅翱 + */ + public void createWorkbook() + { + this.wb = new SXSSFWorkbook(500); + } + + /** + * 鍒涘缓宸ヤ綔琛� + * + * @param sheetNo sheet鏁伴噺 + * @param index 搴忓彿 + */ + public void createSheet(double sheetNo, int index) + { + this.sheet = wb.createSheet(); + this.styles = createStyles(wb); + // 璁剧疆宸ヤ綔琛ㄧ殑鍚嶇О. + if (sheetNo == 0) + { + wb.setSheetName(index, sheetName); + } + else + { + wb.setSheetName(index, sheetName + index); + } + } + + /** + * 鑾峰彇鍗曞厓鏍煎�� + * + * @param row 鑾峰彇鐨勮 + * @param column 鑾峰彇鍗曞厓鏍煎垪鍙� + * @return 鍗曞厓鏍煎�� + */ + public Object getCellValue(Row row, int column) + { + if (row == null) + { + return row; + } + Object val = ""; + try + { + Cell cell = row.getCell(column); + if (Validator.isNotNull(cell)) + { + if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) + { + val = cell.getNumericCellValue(); + if (DateUtil.isCellDateFormatted(cell)) + { + val = DateUtil.getJavaDate((Double) val); // POI Excel 鏃ユ湡鏍煎紡杞崲 + } + else + { + if ((Double) val % 1 != 0) + { + val = new BigDecimal(val.toString()); + } + else + { + val = new DecimalFormat("0").format(val); + } + } + } + else if (cell.getCellType() == CellType.STRING) + { + val = cell.getStringCellValue(); + } + else if (cell.getCellType() == CellType.BOOLEAN) + { + val = cell.getBooleanCellValue(); + } + else if (cell.getCellType() == CellType.ERROR) + { + val = cell.getErrorCellValue(); + } + + } + } + catch (Exception e) + { + return val; + } + return val; + } +} diff --git a/ruoyi-demo/pom.xml b/ruoyi-demo/pom.xml index 4904924..d3909a2 100644 --- a/ruoyi-demo/pom.xml +++ b/ruoyi-demo/pom.xml @@ -5,7 +5,7 @@ <parent> <artifactId>ruoyi-vue-plus</artifactId> <groupId>com.ruoyi</groupId> - <version>${ruoyi-vue-plus.version}</version> + <version>2.5.0</version> </parent> <modelVersion>4.0.0</modelVersion> @@ -25,4 +25,4 @@ </dependencies> -</project> \ No newline at end of file +</project> diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java new file mode 100644 index 0000000..4588f13 --- /dev/null +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java @@ -0,0 +1,70 @@ +package com.ruoyi.demo.controller; + +import com.ruoyi.common.core.domain.AjaxResult; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * spring-cache 婕旂ず妗堜緥 + * + * @author Lion Li + */ +// 绫荤骇鍒� 缂撳瓨缁熶竴閰嶇疆 +//@CacheConfig(cacheNames = "redissonCacheMap") +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@RestController +@RequestMapping("/demo/cache") +public class RedisCacheController { + + /** + * 娴嬭瘯 @Cacheable + * + * 琛ㄧず杩欎釜鏂规硶鏈変簡缂撳瓨鐨勫姛鑳�,鏂规硶鐨勮繑鍥炲�间細琚紦瀛樹笅鏉� + * 涓嬩竴娆¤皟鐢ㄨ鏂规硶鍓�,浼氬幓妫�鏌ユ槸鍚︾紦瀛樹腑宸茬粡鏈夊�� + * 濡傛灉鏈夊氨鐩存帴杩斿洖,涓嶈皟鐢ㄦ柟娉� + * 濡傛灉娌℃湁,灏辫皟鐢ㄦ柟娉�,鐒跺悗鎶婄粨鏋滅紦瀛樿捣鏉� + * 杩欎釜娉ㄨВ銆屼竴鑸敤鍦ㄦ煡璇㈡柟娉曚笂銆� + * + * cacheNames 涓洪厤缃枃浠跺唴 groupId + */ + @Cacheable(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null") + @GetMapping("/test1") + public AjaxResult<String> test1(String key, String value){ + return AjaxResult.success("鎿嶄綔鎴愬姛", value); + } + + /** + * 娴嬭瘯 @CachePut + * + * 鍔犱簡@CachePut娉ㄨВ鐨勬柟娉�,浼氭妸鏂规硶鐨勮繑鍥炲�紁ut鍒扮紦瀛橀噷闈㈢紦瀛樿捣鏉�,渚涘叾瀹冨湴鏂逛娇鐢� + * 瀹冦�岄�氬父鐢ㄥ湪鏂板鏂规硶涓娿�� + * + * cacheNames 涓� 閰嶇疆鏂囦欢鍐� groupId + */ + @CachePut(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null") + @GetMapping("/test2") + public AjaxResult<String> test2(String key, String value){ + return AjaxResult.success("鎿嶄綔鎴愬姛", value); + } + + /** + * 娴嬭瘯 @CacheEvict + * + * 浣跨敤浜咰acheEvict娉ㄨВ鐨勬柟娉�,浼氭竻绌烘寚瀹氱紦瀛� + * 銆屼竴鑸敤鍦ㄦ洿鏂版垨鑰呭垹闄ょ殑鏂规硶涓娿�� + * + * cacheNames 涓� 閰嶇疆鏂囦欢鍐� groupId + */ + @CacheEvict(cacheNames = "redissonCacheMap", key = "#key", condition = "#key != null") + @GetMapping("/test3") + public AjaxResult<String> test3(String key, String value){ + return AjaxResult.success("鎿嶄綔鎴愬姛", value); + } + +} diff --git a/ruoyi-demo/src/main/java/com/ruoyi/demo/feign/fallback/FeignTestFallback.java b/ruoyi-demo/src/main/java/com/ruoyi/demo/feign/fallback/FeignTestFallback.java index 3b4dfd0..0f9e400 100644 --- a/ruoyi-demo/src/main/java/com/ruoyi/demo/feign/fallback/FeignTestFallback.java +++ b/ruoyi-demo/src/main/java/com/ruoyi/demo/feign/fallback/FeignTestFallback.java @@ -7,7 +7,10 @@ /** * feign娴嬭瘯fallback + * 鑷畾涔夊皝瑁呯粨鏋勪綋鐔旀柇 + * 闇�閲嶅啓瑙g爜鍣� 鏍规嵁鑷畾涔夊疄浣� 鑷瑙f瀽鐔旀柇 * + * @see {com.ruoyi.framework.config.FeignConfig#errorDecoder()} * @author Lion Li */ @Slf4j diff --git a/ruoyi-extend/pom.xml b/ruoyi-extend/pom.xml new file mode 100644 index 0000000..e71a426 --- /dev/null +++ b/ruoyi-extend/pom.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>ruoyi-vue-plus</artifactId> + <groupId>com.ruoyi</groupId> + <version>2.5.0</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>ruoyi-extend</artifactId> + <packaging>pom</packaging> + + <modules> + <module>ruoyi-monitor-admin</module> + </modules> + +</project> diff --git a/ruoyi-extend/ruoyi-monitor-admin/Dockerfile b/ruoyi-extend/ruoyi-monitor-admin/Dockerfile new file mode 100644 index 0000000..ef551fe --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/Dockerfile @@ -0,0 +1,13 @@ +FROM anapsix/alpine-java:8_server-jre_unlimited + +MAINTAINER Lion Li + +RUN mkdir -p /ruoyi/monitor + +WORKDIR /ruoyi/monitor + +EXPOSE 9090 + +ADD ./target/ruoyi-monitor-admin.jar ./app.jar + +ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] diff --git a/ruoyi-extend/ruoyi-monitor-admin/pom.xml b/ruoyi-extend/ruoyi-monitor-admin/pom.xml new file mode 100644 index 0000000..e9d48d6 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/pom.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>ruoyi-extend</artifactId> + <groupId>com.ruoyi</groupId> + <version>2.5.0</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <packaging>jar</packaging> + <artifactId>ruoyi-monitor-admin</artifactId> + + <dependencies> + <!-- SpringWeb妯″潡 --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + + <!-- spring security 瀹夊叏璁よ瘉 --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + + <dependency> + <groupId>de.codecentric</groupId> + <artifactId>spring-boot-admin-starter-server</artifactId> + </dependency> + </dependencies> + + <build> + <finalName>${project.artifactId}</finalName> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <version>${spring-boot.version}</version> + <configuration> + <fork>true</fork> <!-- 濡傛灉娌℃湁璇ラ厤缃紝devtools涓嶄細鐢熸晥 --> + </configuration> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>com.spotify</groupId> + <artifactId>docker-maven-plugin</artifactId> + <version>${docker.plugin.version}</version> + <configuration> + <imageName>${docker.namespace}/${project.artifactId}:${project.version}</imageName> + <dockerDirectory>${project.basedir}</dockerDirectory> + <dockerHost>${docker.registry.host}</dockerHost> + <registryUrl>${docker.registry.url}</registryUrl> + <serverId>${docker.registry.url}</serverId> + <resources> + <resource> + <targetPath>/</targetPath> + <directory>${project.build.directory}</directory> + <include>${project.build.finalName}.jar</include> + </resource> + </resources> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/MonitorAdminApplication.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/MonitorAdminApplication.java new file mode 100644 index 0000000..1d1cbca --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/MonitorAdminApplication.java @@ -0,0 +1,19 @@ +package com.ruoyi.monitor.admin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Admin 鐩戞帶鍚姩绋嬪簭 + * + * @author Lion Li + */ +@SpringBootApplication +public class MonitorAdminApplication { + + public static void main(String[] args) { + SpringApplication.run(MonitorAdminApplication.class, args); + System.out.println("Admin 鐩戞帶鍚姩鎴愬姛" ); + } + +} diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/AdminServerConfig.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/AdminServerConfig.java new file mode 100644 index 0000000..e2a9c51 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/AdminServerConfig.java @@ -0,0 +1,31 @@ +package com.ruoyi.monitor.admin.config; + +import de.codecentric.boot.admin.server.config.EnableAdminServer; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; +import org.springframework.boot.task.TaskExecutorBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +/** + * springboot-admin server閰嶇疆绫� + * + * @author Lion Li + */ +@Configuration +@EnableAdminServer +public class AdminServerConfig { + + @Lazy + @Bean(name = TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME) + @ConditionalOnMissingBean(Executor.class) + public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) { + return builder.build(); + } + + +} diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java new file mode 100644 index 0000000..98834a9 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java @@ -0,0 +1,48 @@ +package com.ruoyi.monitor.admin.config; + +import de.codecentric.boot.admin.server.config.AdminServerProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; + +/** + * spring security閰嶇疆 + * + * @author ruoyi + */ +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + private final String adminContextPath; + + public SecurityConfig(AdminServerProperties adminServerProperties) { + this.adminContextPath = adminServerProperties.getContextPath(); + } + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); + successHandler.setTargetUrlParameter("redirectTo"); + successHandler.setDefaultTargetUrl(adminContextPath + "/"); + + httpSecurity.authorizeRequests() + //鎺堜簣瀵规墍鏈夐潤鎬佽祫浜у拰鐧诲綍椤甸潰鐨勫叕鍏辫闂潈闄愩�� + .antMatchers(adminContextPath + "/assets/**").permitAll() + .antMatchers(adminContextPath + "/login").permitAll() + //蹇呴』瀵规瘡涓叾浠栬姹傝繘琛岃韩浠介獙璇� + .anyRequest().authenticated().and() + //閰嶇疆鐧诲綍鍜屾敞閿� + .formLogin().loginPage(adminContextPath + "/login") + .successHandler(successHandler).and() + .logout().logoutUrl(adminContextPath + "/logout").and() + //鍚敤HTTP-Basic鏀寔銆傝繖鏄疭pring Boot Admin Client娉ㄥ唽鎵�蹇呴渶鐨� + .httpBasic().and().csrf().disable() + .headers().frameOptions().disable(); + } + +} diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml new file mode 100644 index 0000000..631f3e7 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml @@ -0,0 +1,11 @@ +server: + port: 9090 + +spring: + security: + user: + name: ruoyi + password: 123456 + boot: + admin: + context-path: /admin diff --git a/ruoyi-framework/pom.xml b/ruoyi-framework/pom.xml index 4313ce5..e7ed991 100644 --- a/ruoyi-framework/pom.xml +++ b/ruoyi-framework/pom.xml @@ -5,7 +5,7 @@ <parent> <artifactId>ruoyi-vue-plus</artifactId> <groupId>com.ruoyi</groupId> - <version>${ruoyi-vue-plus.version}</version> + <version>2.5.0</version> </parent> <modelVersion>4.0.0</modelVersion> diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AdminServerConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AdminServerConfig.java deleted file mode 100644 index 59fed50..0000000 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/AdminServerConfig.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.ruoyi.framework.config; - -import de.codecentric.boot.admin.server.config.EnableAdminServer; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; -import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties; -import org.springframework.boot.task.TaskExecutorBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Lazy; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import org.thymeleaf.dialect.IDialect; -import org.thymeleaf.spring5.ISpringTemplateEngine; -import org.thymeleaf.spring5.SpringTemplateEngine; -import org.thymeleaf.templateresolver.ITemplateResolver; - -import java.util.Comparator; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.concurrent.Executor; -import java.util.stream.Collectors; - -/** - * springboot-admin server閰嶇疆绫� - * - * @author Lion Li - */ -@Configuration -@EnableAdminServer -public class AdminServerConfig { - - @Lazy - @Bean(name = TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME) - @ConditionalOnMissingBean(Executor.class) - public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) { - return builder.build(); - } - - /** - * 瑙e喅 admin 涓� 椤圭洰 椤甸潰鐨勪氦鍙夊紩鐢� 灏� admin 鐨勮矾鐢辨斁鍒版渶鍚� - * @param properties - * @param templateResolvers - * @param dialects - * @return - */ - @Bean - @ConditionalOnMissingBean(ISpringTemplateEngine.class) - SpringTemplateEngine templateEngine(ThymeleafProperties properties, - ObjectProvider<ITemplateResolver> templateResolvers, ObjectProvider<IDialect> dialects) { - SpringTemplateEngine engine = new SpringTemplateEngine(); - engine.setEnableSpringELCompiler(properties.isEnableSpringElCompiler()); - engine.setRenderHiddenMarkersBeforeCheckboxes(properties.isRenderHiddenMarkersBeforeCheckboxes()); - templateResolvers.orderedStream().forEach(engine::addTemplateResolver); - dialects.orderedStream().forEach(engine::addDialect); - Set<ITemplateResolver> templateResolvers1 = engine.getTemplateResolvers(); - templateResolvers1 = templateResolvers1.stream() - .sorted(Comparator.comparing(ITemplateResolver::getOrder)) - .collect(Collectors.toCollection(LinkedHashSet::new)); - engine.setTemplateResolvers(templateResolvers1); - return engine; - } -} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FeignConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FeignConfig.java index f10769b..14db1c9 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FeignConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FeignConfig.java @@ -54,4 +54,40 @@ return new Retryer.Default(); } +// /** +// * 鑷畾涔夊紓甯歌В鐮佸櫒 +// * 鐢ㄤ簬鑷畾涔夎繑鍥炰綋寮傚父鐔旀柇 +// */ +// @Bean +// public ErrorDecoder errorDecoder() { +// return new CustomErrorDecoder(); +// } +// +// +// /** +// * 鑷畾涔夎繑鍥炰綋瑙g爜鍣� +// */ +// @Slf4j +// public static class CustomErrorDecoder implements ErrorDecoder { +// +// @Override +// public Exception decode(String methodKey, Response response) { +// Exception exception = null; +// try { +// // 鑾峰彇鍘熷鐨勮繑鍥炲唴瀹� +// String json = JsonUtils.toJsonString(response.body().asReader(StandardCharsets.UTF_8)); +// exception = new RuntimeException(json); +// // 灏嗚繑鍥炲唴瀹瑰弽搴忓垪鍖栦负Result锛岃繖閲屽簲鏍规嵁鑷韩椤圭洰浣滀慨鏀� +// AjaxResult result = JsonUtils.parseObject(json, AjaxResult.class); +// // 涓氬姟寮傚父鎶涘嚭绠�鍗曠殑 RuntimeException锛屼繚鐣欏師鏉ラ敊璇俊鎭� +// if (result.getCode() != 200) { +// exception = new RuntimeException(result.getMsg()); +// } +// } catch (IOException e) { +// log.error(e.getMessage(), e); +// } +// return exception; +// } +// } + } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java index 95c7572..bc28657 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -78,8 +79,13 @@ */ @Bean public CacheManager cacheManager(RedissonClient redissonClient) { + List<RedissonProperties.CacheGroup> cacheGroup = redissonProperties.getCacheGroup(); Map<String, CacheConfig> config = new HashMap<>(); - config.put("redissonCacheMap", new CacheConfig(30*60*1000, 10*60*1000)); + for (RedissonProperties.CacheGroup group : cacheGroup) { + CacheConfig cacheConfig = new CacheConfig(group.getTtl(), group.getMaxIdleTime()); + cacheConfig.setMaxSize(group.getMaxSize()); + config.put(group.getGroupId(), cacheConfig); + } return new RedissonSpringCacheManager(redissonClient, config, JsonJacksonCodec.INSTANCE); } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java index 79ade78..0a8337e 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java @@ -3,7 +3,6 @@ import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter; import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl; import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl; -import de.codecentric.boot.admin.server.config.AdminServerProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpMethod; @@ -57,9 +56,6 @@ @Autowired private CorsFilter corsFilter; - @Autowired - private AdminServerProperties adminServerProperties; - /** * 瑙e喅 鏃犳硶鐩存帴娉ㄥ叆 AuthenticationManager * @@ -104,12 +100,13 @@ .antMatchers("/login", "/captchaImage").anonymous() .antMatchers( HttpMethod.GET, + "/", "/*.html", "/**/*.html", "/**/*.css", - "/**/*.js" + "/**/*.js", + "/profile/**" ).permitAll() - .antMatchers("/profile/**").anonymous() .antMatchers("/common/download**").anonymous() .antMatchers("/common/download/resource**").anonymous() .antMatchers("/doc.html").anonymous() @@ -117,9 +114,6 @@ .antMatchers("/webjars/**").anonymous() .antMatchers("/*/api-docs").anonymous() .antMatchers("/druid/**").anonymous() - // Spring Boot Admin Server 鐨勫畨鍏ㄩ厤缃� - .antMatchers(adminServerProperties.getContextPath()).anonymous() - .antMatchers(adminServerProperties.getContextPath() + "/**").anonymous() // Spring Boot Actuator 鐨勫畨鍏ㄩ厤缃� .antMatchers("/actuator").anonymous() .antMatchers("/actuator/**").anonymous() diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java index 99db89e..b6e289d 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/RedissonProperties.java @@ -2,10 +2,11 @@ import lombok.Data; import lombok.NoArgsConstructor; -import org.redisson.client.codec.Codec; import org.redisson.config.TransportMode; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; + +import java.util.List; /** * Redisson 閰嶇疆灞炴�� @@ -36,6 +37,11 @@ * 鍗曟満鏈嶅姟閰嶇疆 */ private SingleServerConfig singleServerConfig; + + /** + * 缂撳瓨缁� + */ + private List<CacheGroup> cacheGroup; @Data @NoArgsConstructor @@ -98,4 +104,30 @@ } + @Data + @NoArgsConstructor + public static class CacheGroup { + + /** + * 缁刬d + */ + private String groupId; + + /** + * 缁勮繃鏈熸椂闂� + */ + private long ttl; + + /** + * 缁勬渶澶х┖闂叉椂闂� + */ + private long maxIdleTime; + + /** + * 缁勬渶澶ч暱搴� + */ + private int maxSize; + + } + } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java index 4797a64..2479293 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/mybatisplus/CreateAndUpdateMetaObjectHandler.java @@ -1,6 +1,8 @@ package com.ruoyi.framework.mybatisplus; +import cn.hutool.http.HttpStatus; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.ruoyi.common.exception.CustomException; import com.ruoyi.common.utils.SecurityUtils; import org.apache.ibatis.reflection.MetaObject; @@ -8,6 +10,7 @@ /** * MP娉ㄥ叆澶勭悊鍣� + * * @author Lion Li * @date 2021/4/25 */ @@ -15,30 +18,38 @@ @Override public void insertFill(MetaObject metaObject) { - //鏍规嵁灞炴�у悕瀛楄缃濉厖鐨勫�� - if (metaObject.hasGetter("createTime")) { - if (metaObject.getValue("createTime") == null) { - this.setFieldValByName("createTime", new Date(), metaObject); + try { + //鏍规嵁灞炴�у悕瀛楄缃濉厖鐨勫�� + if (metaObject.hasGetter("createTime")) { + if (metaObject.getValue("createTime") == null) { + this.setFieldValByName("createTime", new Date(), metaObject); + } } - } - if (metaObject.hasGetter("createBy")) { - if (metaObject.getValue("createBy") == null) { - this.setFieldValByName("createBy", SecurityUtils.getUsername(), metaObject); + if (metaObject.hasGetter("createBy")) { + if (metaObject.getValue("createBy") == null) { + this.setFieldValByName("createBy", SecurityUtils.getUsername(), metaObject); + } } + } catch (Exception e) { + throw new CustomException("鑷姩娉ㄥ叆寮傚父 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); } } @Override public void updateFill(MetaObject metaObject) { - if (metaObject.hasGetter("updateBy")) { - if (metaObject.getValue("updateBy") == null) { - this.setFieldValByName("updateBy", SecurityUtils.getUsername(), metaObject); + try { + if (metaObject.hasGetter("updateBy")) { + if (metaObject.getValue("updateBy") == null) { + this.setFieldValByName("updateBy", SecurityUtils.getUsername(), metaObject); + } } - } - if (metaObject.hasGetter("updateTime")) { - if (metaObject.getValue("updateTime") == null) { - this.setFieldValByName("updateTime", new Date(), metaObject); + if (metaObject.hasGetter("updateTime")) { + if (metaObject.getValue("updateTime") == null) { + this.setFieldValByName("updateTime", new Date(), metaObject); + } } + } catch (Exception e) { + throw new CustomException("鑷姩娉ㄥ叆寮傚父 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); } } diff --git a/ruoyi-generator/pom.xml b/ruoyi-generator/pom.xml index 8073706..642dfec 100644 --- a/ruoyi-generator/pom.xml +++ b/ruoyi-generator/pom.xml @@ -5,7 +5,7 @@ <parent> <artifactId>ruoyi-vue-plus</artifactId> <groupId>com.ruoyi</groupId> - <version>${ruoyi-vue-plus.version}</version> + <version>2.5.0</version> </parent> <modelVersion>4.0.0</modelVersion> diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java index 4da27e8..5fcdd3b 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java @@ -182,9 +182,9 @@ List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); for (GenTableColumn column : genTableColumns) { GenUtils.initColumnField(column, table); - genTableColumnMapper.insert(column); } - } + genTableColumnMapper.insertAll(genTableColumns); + } } } catch (Exception e) { throw new CustomException("瀵煎叆澶辫触锛�" + e.getMessage()); @@ -258,7 +258,7 @@ // 鑾峰彇妯℃澘鍒楄〃 List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory()); for (String template : templates) { - if (!StrUtil.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm")) { + if (!StrUtil.containsAny("sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm", template)) { // 娓叉煋妯℃澘 StringWriter sw = new StringWriter(); Template tpl = Velocity.getTemplate(template, Constants.UTF8); @@ -290,9 +290,9 @@ dbTableColumns.forEach(column -> { if (!tableColumnNames.contains(column.getColumnName())) { GenUtils.initColumnField(column, table); - genTableColumnMapper.insert(column); - } - }); + } + }); + genTableColumnMapper.insertAll(tableColumns); List<GenTableColumn> delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList()); if (CollUtil.isNotEmpty(delColumns)) { diff --git a/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm b/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm index 6d4f40f..6f8ff7b 100644 --- a/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm @@ -11,8 +11,6 @@ * @author ${author} * @date ${datetime} */ -// 濡備娇闇�鍒囨崲鏁版嵁婧� 璇峰嬁浣跨敤缂撳瓨 浼氶�犳垚鏁版嵁涓嶄竴鑷寸幇璞� -@CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class) public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}> { } diff --git a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm index d43c2ce..cedab30 100644 --- a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm +++ b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm @@ -256,52 +256,16 @@ import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}"; import Treeselect from "@riophae/vue-treeselect"; import "@riophae/vue-treeselect/dist/vue-treeselect.css"; -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "imageUpload") -import ImageUpload from '@/components/ImageUpload'; -#break -#end -#end -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "fileUpload") -import FileUpload from '@/components/FileUpload'; -#break -#end -#end -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "editor") -import Editor from '@/components/Editor'; -#break -#end -#end export default { name: "${BusinessName}", components: { -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "imageUpload") - ImageUpload, -#break -#end -#end -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "fileUpload") - FileUpload, -#break -#end -#end -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "editor") - Editor, -#break -#end -#end Treeselect }, data() { return { - //鎸夐挳loading - buttonLoading: false, + // 鎸夐挳loading + buttonLoading: false, // 閬僵灞� loading: true, // 鏄剧ず鎼滅储鏉′欢 @@ -510,17 +474,19 @@ #end if (this.form.${pkColumn.javaField} != null) { update${BusinessName}(this.form).then(response => { - this.buttonLoading = false; this.msgSuccess("淇敼鎴愬姛"); this.open = false; this.getList(); + }).finally(() => { + this.buttonLoading = false; }); } else { add${BusinessName}(this.form).then(response => { - this.buttonLoading = false; this.msgSuccess("鏂板鎴愬姛"); this.open = false; this.getList(); + }).finally(() => { + this.buttonLoading = false; }); } } diff --git a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm index abc799e..12a9a63 100644 --- a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm +++ b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm @@ -308,51 +308,13 @@ <script> import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}"; -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "imageUpload") -import ImageUpload from '@/components/ImageUpload'; -#break -#end -#end -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "fileUpload") -import FileUpload from '@/components/FileUpload'; -#break -#end -#end -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "editor") -import Editor from '@/components/Editor'; -#break -#end -#end export default { name: "${BusinessName}", - components: { -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "imageUpload") - ImageUpload, -#break -#end -#end -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "fileUpload") - FileUpload, -#break -#end -#end -#foreach($column in $columns) -#if($column.insert && !$column.pk && $column.htmlType == "editor") - Editor, -#break -#end -#end - }, data() { return { - //鎸夐挳loading - buttonLoading: false, + // 鎸夐挳loading + buttonLoading: false, // 閬僵灞� loading: true, // 瀵煎嚭閬僵灞� @@ -567,17 +529,19 @@ #end if (this.form.${pkColumn.javaField} != null) { update${BusinessName}(this.form).then(response => { - this.buttonLoading = false; this.msgSuccess("淇敼鎴愬姛"); this.open = false; this.getList(); + }).finally(() => { + this.buttonLoading = false; }); } else { add${BusinessName}(this.form).then(response => { - this.buttonLoading = false; this.msgSuccess("鏂板鎴愬姛"); this.open = false; this.getList(); + }).finally(() => { + this.buttonLoading = false; }); } } diff --git a/ruoyi-quartz/pom.xml b/ruoyi-quartz/pom.xml index cfcbffc..522a84e 100644 --- a/ruoyi-quartz/pom.xml +++ b/ruoyi-quartz/pom.xml @@ -5,7 +5,7 @@ <parent> <artifactId>ruoyi-vue-plus</artifactId> <groupId>com.ruoyi</groupId> - <version>${ruoyi-vue-plus.version}</version> + <version>2.5.0</version> </parent> <modelVersion>4.0.0</modelVersion> diff --git a/ruoyi-system/pom.xml b/ruoyi-system/pom.xml index 2f5579f..85576db 100644 --- a/ruoyi-system/pom.xml +++ b/ruoyi-system/pom.xml @@ -5,7 +5,7 @@ <parent> <artifactId>ruoyi-vue-plus</artifactId> <groupId>com.ruoyi</groupId> - <version>${ruoyi-vue-plus.version}</version> + <version>2.5.0</version> </parent> <modelVersion>4.0.0</modelVersion> diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java index e389f5d..495db54 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java @@ -1,6 +1,8 @@ package com.ruoyi.system.domain.vo; -import lombok.*; +import com.ruoyi.common.utils.StringUtils; +import lombok.Data; +import lombok.NoArgsConstructor; import lombok.experimental.Accessors; /** @@ -28,6 +30,11 @@ */ private boolean noCache; + /** + * 鍐呴摼鍦板潃锛坔ttp(s)://寮�澶达級 + */ + private String link; + public MetaVo(String title, String icon) { this.title = title; this.icon = icon; @@ -39,4 +46,19 @@ this.noCache = noCache; } + public MetaVo(String title, String icon, String link) { + this.title = title; + this.icon = icon; + this.link = link; + } + + public MetaVo(String title, String icon, boolean noCache, String link) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + if (StringUtils.ishttp(link)) { + this.link = link; + } + } + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java index 17b17b0..cba0668 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java @@ -25,6 +25,22 @@ public List<SysUser> selectUserList(SysUser sysUser); /** + * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鏈凡閰嶇敤鎴疯鑹插垪琛� + * + * @param user 鐢ㄦ埛淇℃伅 + * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅 + */ + public Page<SysUser> selectAllocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user); + + /** + * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛� + * + * @param user 鐢ㄦ埛淇℃伅 + * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅 + */ + public Page<SysUser> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user); + + /** * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴� * * @param userName 鐢ㄦ埛鍚� diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java index 2f46822..9d02ceb 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java @@ -3,6 +3,8 @@ import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.mybatisplus.core.IServicePlus; import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.entity.SysRole; +import com.ruoyi.system.domain.SysUserRole; import java.util.List; import java.util.Set; @@ -26,7 +28,15 @@ public List<SysRole> selectRoleList(SysRole role); /** - * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊 + * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊鍒楄〃 + * + * @param userId 鐢ㄦ埛ID + * @return 瑙掕壊鍒楄〃 + */ + public List<SysRole> selectRolesByUserId(Long userId); + + /** + * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊鏉冮檺 * * @param userId 鐢ㄦ埛ID * @return 鏉冮檺鍒楄〃 @@ -134,4 +144,30 @@ * @return 缁撴灉 */ public int deleteRoleByIds(Long[] roleIds); + + /** + * 鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊 + * + * @param userRole 鐢ㄦ埛鍜岃鑹插叧鑱斾俊鎭� + * @return 缁撴灉 + */ + public int deleteAuthUser(SysUserRole userRole); + + /** + * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊 + * + * @param roleId 瑙掕壊ID + * @param userIds 闇�瑕佸彇娑堟巿鏉冪殑鐢ㄦ埛鏁版嵁ID + * @return 缁撴灉 + */ + public int deleteAuthUsers(Long roleId, Long[] userIds); + + /** + * 鎵归噺閫夋嫨鎺堟潈鐢ㄦ埛瑙掕壊 + * + * @param roleId 瑙掕壊ID + * @param userIds 闇�瑕佸垹闄ょ殑鐢ㄦ埛鏁版嵁ID + * @return 缁撴灉 + */ + public int insertAuthUsers(Long roleId, Long[] userIds); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java index 4c67091..e277d10 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java @@ -25,6 +25,22 @@ public List<SysUser> selectUserList(SysUser user); /** + * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛� + * + * @param user 鐢ㄦ埛淇℃伅 + * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅 + */ + public TableDataInfo<SysUser> selectAllocatedList(SysUser user); + + /** + * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛� + * + * @param user 鐢ㄦ埛淇℃伅 + * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅 + */ + public TableDataInfo<SysUser> selectUnallocatedList(SysUser user); + + /** * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴� * * @param userName 鐢ㄦ埛鍚� @@ -104,6 +120,14 @@ public int updateUser(SysUser user); /** + * 鐢ㄦ埛鎺堟潈瑙掕壊 + * + * @param userId 鐢ㄦ埛ID + * @param roleIds 瑙掕壊缁� + */ + public void insertUserAuth(Long userId, Long[] roleIds); + + /** * 淇敼鐢ㄦ埛鐘舵�� * * @param user 鐢ㄦ埛淇℃伅 @@ -123,7 +147,7 @@ * 淇敼鐢ㄦ埛澶村儚 * * @param userName 鐢ㄦ埛鍚� - * @param avatar 澶村儚鍦板潃 + * @param avatar 澶村儚鍦板潃 * @return 缁撴灉 */ public boolean updateUserAvatar(String userName, String avatar); @@ -164,9 +188,9 @@ /** * 瀵煎叆鐢ㄦ埛鏁版嵁 * - * @param userList 鐢ㄦ埛鏁版嵁鍒楄〃 + * @param userList 鐢ㄦ埛鏁版嵁鍒楄〃 * @param isUpdateSupport 鏄惁鏇存柊鏀寔锛屽鏋滃凡瀛樺湪锛屽垯杩涜鏇存柊鏁版嵁 - * @param operName 鎿嶄綔鐢ㄦ埛 + * @param operName 鎿嶄綔鐢ㄦ埛 * @return 缁撴灉 */ public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java index f8b4706..f23e661 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java @@ -3,6 +3,7 @@ import cn.hutool.core.lang.Validator; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.domain.TreeSelect; import com.ruoyi.common.core.domain.entity.SysMenu; @@ -10,6 +11,7 @@ import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.domain.SysRoleMenu; import com.ruoyi.system.domain.vo.MetaVo; import com.ruoyi.system.domain.vo.RouterVo; @@ -135,7 +137,7 @@ router.setName(getRouteName(menu)); router.setPath(getRouterPath(menu)); router.setComponent(getComponent(menu)); - router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals("1", menu.getIsCache()))); + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals("1", menu.getIsCache()), menu.getPath())); List<SysMenu> cMenus = menu.getChildren(); if (!cMenus.isEmpty() && UserConstants.TYPE_DIR.equals(menu.getMenuType())) { router.setAlwaysShow(true); @@ -148,7 +150,19 @@ children.setPath(menu.getPath()); children.setComponent(menu.getComponent()); children.setName(StrUtil.upperFirst(menu.getPath())); - children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals("1", menu.getIsCache()))); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals("1", menu.getIsCache()), menu.getPath())); + childrenList.add(children); + router.setChildren(childrenList); + } else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) { + router.setMeta(null); + router.setPath("/inner"); + List<RouterVo> childrenList = new ArrayList<RouterVo>(); + RouterVo children = new RouterVo(); + String routerPath = StringUtils.replaceEach(menu.getPath(), new String[] { Constants.HTTP, Constants.HTTPS }, new String[] { "", "" }); + children.setPath(routerPath); + children.setComponent(UserConstants.INNER_LINK); + children.setName(StringUtils.capitalize(routerPath)); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath())); childrenList.add(children); router.setChildren(childrenList); } @@ -305,6 +319,10 @@ */ public String getRouterPath(SysMenu menu) { String routerPath = menu.getPath(); + // 鍐呴摼鎵撳紑澶栫綉鏂瑰紡 + if (menu.getParentId().intValue() != 0 && isInnerLink(menu)) { + routerPath = StringUtils.replaceEach(routerPath, new String[] { Constants.HTTP, Constants.HTTPS }, new String[] { "", "" }); + } // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓虹洰褰曪級 if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType()) && UserConstants.NO_FRAME.equals(menu.getIsFrame())) { @@ -327,7 +345,9 @@ String component = UserConstants.LAYOUT; if (StrUtil.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) { component = menu.getComponent(); - } else if (StrUtil.isEmpty(menu.getComponent()) && isParentView(menu)) { + } else if (StrUtil.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu)) { + component = UserConstants.INNER_LINK; + } else if (StrUtil.isEmpty(menu.getComponent()) && isParentView(menu)) { component = UserConstants.PARENT_VIEW; } return component; @@ -345,6 +365,16 @@ } /** + * 鏄惁涓哄唴閾剧粍浠� + * + * @param menu 鑿滃崟淇℃伅 + * @return 缁撴灉 + */ + public boolean isInnerLink(SysMenu menu) { + return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath()); + } + + /** * 鏄惁涓簆arent_view缁勪欢 * * @param menu 鑿滃崟淇℃伅 @@ -357,7 +387,7 @@ /** * 鏍规嵁鐖惰妭鐐圭殑ID鑾峰彇鎵�鏈夊瓙鑺傜偣 * - * @param list 鍒嗙被琛� + * @param list 鍒嗙被琛� * @param parentId 浼犲叆鐨勭埗鑺傜偣ID * @return String */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java index 1bac225..df024ae 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java @@ -60,6 +60,27 @@ } /** + * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊 + * + * @param userId 鐢ㄦ埛ID + * @return 瑙掕壊鍒楄〃 + */ + @Override + public List<SysRole> selectRolesByUserId(Long userId) { + List<SysRole> userRoles = baseMapper.selectRolePermissionByUserId(userId); + List<SysRole> roles = selectRoleAll(); + for (SysRole role : roles) { + for (SysRole userRole : userRoles) { + if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) { + role.setFlag(true); + break; + } + } + } + return roles; + } + + /** * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺 * * @param userId 鐢ㄦ埛ID @@ -305,4 +326,51 @@ roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().in(SysRoleDept::getRoleId, ids)); return baseMapper.deleteBatchIds(ids); } + + /** + * 鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊 + * + * @param userRole 鐢ㄦ埛鍜岃鑹插叧鑱斾俊鎭� + * @return 缁撴灉 + */ + @Override + public int deleteAuthUser(SysUserRole userRole) { + return userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>() + .eq(SysUserRole::getRoleId, userRole.getRoleId()) + .eq(SysUserRole::getUserId, userRole.getUserId())); + } + + /** + * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊 + * + * @param roleId 瑙掕壊ID + * @param userIds 闇�瑕佸彇娑堟巿鏉冪殑鐢ㄦ埛鏁版嵁ID + * @return 缁撴灉 + */ + @Override + public int deleteAuthUsers(Long roleId, Long[] userIds) { + return userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>() + .eq(SysUserRole::getRoleId, roleId) + .in(SysUserRole::getUserId, Arrays.asList(userIds))); + } + + /** + * 鎵归噺閫夋嫨鎺堟潈鐢ㄦ埛瑙掕壊 + * + * @param roleId 瑙掕壊ID + * @param userIds 闇�瑕佸垹闄ょ殑鐢ㄦ埛鏁版嵁ID + * @return 缁撴灉 + */ + @Override + public int insertAuthUsers(Long roleId, Long[] userIds) { + // 鏂板鐢ㄦ埛涓庤鑹茬鐞� + List<SysUserRole> list = new ArrayList<SysUserRole>(); + for (Long userId : userIds) { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + list.add(ur); + } + return userRoleMapper.insertAll(list); + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index 7363040..b5bcb70 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -70,6 +70,30 @@ } /** + * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛� + * + * @param user 鐢ㄦ埛淇℃伅 + * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u", isUser = true) + public TableDataInfo<SysUser> selectAllocatedList(SysUser user) { + return PageUtils.buildDataInfo(baseMapper.selectAllocatedList(PageUtils.buildPage(), user)); + } + + /** + * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛� + * + * @param user 鐢ㄦ埛淇℃伅 + * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u", isUser = true) + public TableDataInfo<SysUser> selectUnallocatedList(SysUser user) { + return PageUtils.buildDataInfo(baseMapper.selectUnallocatedList(PageUtils.buildPage(), user)); + } + + /** * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴� * * @param userName 鐢ㄦ埛鍚� @@ -232,6 +256,21 @@ } /** + * 鐢ㄦ埛鎺堟潈瑙掕壊 + * + * @param userId 鐢ㄦ埛ID + * @param roleIds 瑙掕壊缁� + */ + @Override + @Transactional + public void insertUserAuth(Long userId, Long[] roleIds) + { + userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>() + .eq(SysUserRole::getUserId, userId)); + insertUserRole(userId, roleIds); + } + + /** * 淇敼鐢ㄦ埛鐘舵�� * * @param user 鐢ㄦ埛淇℃伅 @@ -257,7 +296,7 @@ * 淇敼鐢ㄦ埛澶村儚 * * @param userName 鐢ㄦ埛鍚� - * @param avatar 澶村儚鍦板潃 + * @param avatar 澶村儚鍦板潃 * @return 缁撴灉 */ @Override @@ -339,6 +378,28 @@ } /** + * 鏂板鐢ㄦ埛瑙掕壊淇℃伅 + * + * @param userId 鐢ㄦ埛ID + * @param roleIds 瑙掕壊缁� + */ + public void insertUserRole(Long userId, Long[] roleIds) { + if (Validator.isNotNull(roleIds)) { + // 鏂板鐢ㄦ埛涓庤鑹茬鐞� + List<SysUserRole> list = new ArrayList<SysUserRole>(); + for (Long roleId : roleIds) { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + list.add(ur); + } + if (list.size() > 0) { + userRoleMapper.insertAll(list); + } + } + } + + /** * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛 * * @param userId 鐢ㄦ埛ID @@ -377,9 +438,9 @@ /** * 瀵煎叆鐢ㄦ埛鏁版嵁 * - * @param userList 鐢ㄦ埛鏁版嵁鍒楄〃 + * @param userList 鐢ㄦ埛鏁版嵁鍒楄〃 * @param isUpdateSupport 鏄惁鏇存柊鏀寔锛屽鏋滃凡瀛樺湪锛屽垯杩涜鏇存柊鏁版嵁 - * @param operName 鎿嶄綔鐢ㄦ埛 + * @param operName 鎿嶄綔鐢ㄦ埛 * @return 缁撴灉 */ @Override diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml index df59332..5e11278 100644 --- a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -75,9 +75,9 @@ r.data_scope, r.status as role_status from sys_user u - left join sys_dept d on u.dept_id = d.dept_id - left join sys_user_role ur on u.user_id = ur.user_id - left join sys_role r on r.role_id = ur.role_id + left join sys_dept d on u.dept_id = d.dept_id + left join sys_user_role ur on u.user_id = ur.user_id + left join sys_role r on r.role_id = ur.role_id </sql> <select id="selectPageUserList" parameterType="SysUser" resultMap="SysUserResult"> @@ -142,6 +142,45 @@ </if> </select> + <select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult"> + select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time + from sys_user u + left join sys_dept d on u.dept_id = d.dept_id + left join sys_user_role ur on u.user_id = ur.user_id + left join sys_role r on r.role_id = ur.role_id + where u.del_flag = '0' and r.role_id = #{user.roleId} + <if test="user.userName != null and user.userName != ''"> + AND u.user_name like concat('%', #{user.userName}, '%') + </if> + <if test="user.phonenumber != null and user.phonenumber != ''"> + AND u.phonenumber like concat('%', #{user.phonenumber}, '%') + </if> + <!-- 鏁版嵁鑼冨洿杩囨护 --> + <if test="user.params.dataScope != null and user.params.dataScope != ''"> + AND ( ${user.params.dataScope} ) + </if> + </select> + + <select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult"> + select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time + from sys_user u + left join sys_dept d on u.dept_id = d.dept_id + left join sys_user_role ur on u.user_id = ur.user_id + left join sys_role r on r.role_id = ur.role_id + where u.del_flag = '0' and (r.role_id != #{user.roleId} or r.role_id IS NULL) + and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = #{user.roleId}) + <if test="user.userName != null and user.userName != ''"> + AND u.user_name like concat('%', #{user.userName}, '%') + </if> + <if test="user.phonenumber != null and user.phonenumber != ''"> + AND u.phonenumber like concat('%', #{user.phonenumber}, '%') + </if> + <!-- 鏁版嵁鑼冨洿杩囨护 --> + <if test="user.params.dataScope != null and user.params.dataScope != ''"> + AND ( ${user.params.dataScope} ) + </if> + </select> + <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult"> <include refid="selectUserVo"/> where u.user_name = #{userName} diff --git a/ruoyi-ui/.env.development b/ruoyi-ui/.env.development index abb97d4..a1a508d 100644 --- a/ruoyi-ui/.env.development +++ b/ruoyi-ui/.env.development @@ -7,5 +7,8 @@ # 鑻ヤ緷绠$悊绯荤粺/寮�鍙戠幆澧� VUE_APP_BASE_API = '/dev-api' +# 鐩戞帶鍦板潃 +VUE_APP_MONITRO_ADMIN = 'http://localhost:9090/admin/login' + # 璺敱鎳掑姞杞� VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/ruoyi-ui/.env.production b/ruoyi-ui/.env.production index 7179b32..b6eec53 100644 --- a/ruoyi-ui/.env.production +++ b/ruoyi-ui/.env.production @@ -4,5 +4,8 @@ # 鐢熶骇鐜閰嶇疆 ENV = 'production' +# 鐩戞帶鍦板潃 +VUE_APP_MONITRO_ADMIN = '/admin/login' + # 鑻ヤ緷绠$悊绯荤粺/鐢熶骇鐜 VUE_APP_BASE_API = '/prod-api' diff --git a/ruoyi-ui/.env.staging b/ruoyi-ui/.env.staging index b5723d7..e74ce6c 100644 --- a/ruoyi-ui/.env.staging +++ b/ruoyi-ui/.env.staging @@ -6,5 +6,8 @@ # 娴嬭瘯鐜閰嶇疆 ENV = 'staging' +# 鐩戞帶鍦板潃 +VUE_APP_MONITRO_ADMIN = '/admin/login' + # 鑻ヤ緷绠$悊绯荤粺/娴嬭瘯鐜 VUE_APP_BASE_API = '/stage-api' diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json index af8db7e..648b172 100644 --- a/ruoyi-ui/package.json +++ b/ruoyi-ui/package.json @@ -1,6 +1,6 @@ { "name": "ruoyi-vue-plus", - "version": "2.4.0", + "version": "2.5.0", "description": "RuoYi-Vue-Plus鍚庡彴绠$悊绯荤粺", "author": "LionLi", "license": "MIT", diff --git a/ruoyi-ui/src/api/system/role.js b/ruoyi-ui/src/api/system/role.js index 463501c..c669ac4 100644 --- a/ruoyi-ui/src/api/system/role.js +++ b/ruoyi-ui/src/api/system/role.js @@ -72,4 +72,50 @@ method: 'get', params: query }) -} \ No newline at end of file +} + + +// 鏌ヨ瑙掕壊宸叉巿鏉冪敤鎴峰垪琛� +export function allocatedUserList(query) { + return request({ + url: '/system/role/authUser/allocatedList', + method: 'get', + params: query + }) +} + +// 鏌ヨ瑙掕壊鏈巿鏉冪敤鎴峰垪琛� +export function unallocatedUserList(query) { + return request({ + url: '/system/role/authUser/unallocatedList', + method: 'get', + params: query + }) +} + +// 鍙栨秷鐢ㄦ埛鎺堟潈瑙掕壊 +export function authUserCancel(data) { + return request({ + url: '/system/role/authUser/cancel', + method: 'put', + data: data + }) +} + +// 鎵归噺鍙栨秷鐢ㄦ埛鎺堟潈瑙掕壊 +export function authUserCancelAll(data) { + return request({ + url: '/system/role/authUser/cancelAll', + method: 'put', + params: data + }) +} + +// 鎺堟潈鐢ㄦ埛閫夋嫨 +export function authUserSelectAll(data) { + return request({ + url: '/system/role/authUser/selectAll', + method: 'put', + params: data + }) +} diff --git a/ruoyi-ui/src/api/system/user.js b/ruoyi-ui/src/api/system/user.js index 3b9a776..37f4eb3 100644 --- a/ruoyi-ui/src/api/system/user.js +++ b/ruoyi-ui/src/api/system/user.js @@ -125,3 +125,20 @@ method: 'get' }) } + +// 鏌ヨ鎺堟潈瑙掕壊 +export function getAuthRole(userId) { + return request({ + url: '/system/user/authRole/' + userId, + method: 'get' + }) +} + +// 淇濆瓨鎺堟潈瑙掕壊 +export function updateAuthRole(data) { + return request({ + url: '/system/user/authRole', + method: 'put', + params: data + }) +} diff --git a/ruoyi-ui/src/assets/styles/ruoyi.scss b/ruoyi-ui/src/assets/styles/ruoyi.scss index dee6d09..c4b4365 100644 --- a/ruoyi-ui/src/assets/styles/ruoyi.scss +++ b/ruoyi-ui/src/assets/styles/ruoyi.scss @@ -53,6 +53,13 @@ margin-left: 20px; } +.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { + font-family: inherit; + font-weight: 500; + line-height: 1.1; + color: inherit; +} + .el-dialog:not(.is-fullscreen){ margin-top: 6vh !important; } @@ -120,6 +127,17 @@ width: inherit; } +/** 琛ㄦ牸鏇村鎿嶄綔涓嬫媺鏍峰紡 */ +.el-table .el-dropdown-link { + cursor: pointer; + color: #1890ff; + margin-left: 5px; +} + +.el-table .el-dropdown, .el-icon-arrow-down { + font-size: 12px; +} + .el-tree-node__content > .el-checkbox { margin-right: 8px; } diff --git a/ruoyi-ui/src/components/Editor/index.vue b/ruoyi-ui/src/components/Editor/index.vue index d63a48d..98b9fa7 100644 --- a/ruoyi-ui/src/components/Editor/index.vue +++ b/ruoyi-ui/src/components/Editor/index.vue @@ -9,7 +9,7 @@ :headers="headers" style="display: none" ref="upload" - v-if="this.uploadUrl" + v-if="this.type == 'url'" > </el-upload> <div class="editor" ref="editor" :style="styles"></div> @@ -46,14 +46,15 @@ type: Boolean, default: false, }, - /* 涓婁紶鍦板潃 */ - uploadUrl: { + /* 绫诲瀷锛坆ase64鏍煎紡銆乽rl鏍煎紡锛� */ + type: { type: String, - default: "", + default: "url", } }, data() { return { + uploadUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃 headers: { Authorization: "Bearer " + getToken() }, @@ -119,7 +120,7 @@ const editor = this.$refs.editor; this.Quill = new Quill(editor, this.options); // 濡傛灉璁剧疆浜嗕笂浼犲湴鍧�鍒欒嚜瀹氫箟鍥剧墖涓婁紶浜嬩欢 - if (this.uploadUrl) { + if (this.type == 'url') { let toolbar = this.Quill.getModule("toolbar"); toolbar.addHandler("image", (value) => { this.uploadType = "image"; @@ -165,7 +166,7 @@ // 鑾峰彇鍏夋爣鎵�鍦ㄤ綅缃� let length = quill.getSelection().index; // 鎻掑叆鍥剧墖 res.url涓烘湇鍔″櫒杩斿洖鐨勫浘鐗囧湴鍧� - quill.insertEmbed(length, "image", res.url); + quill.insertEmbed(length, "image", process.env.VUE_APP_BASE_API + res.data.fileName); // 璋冩暣鍏夋爣鍒版渶鍚� quill.setSelection(length + 1); } else { diff --git a/ruoyi-ui/src/components/FileUpload/index.vue b/ruoyi-ui/src/components/FileUpload/index.vue index 81e2b3a..d47fb98 100644 --- a/ruoyi-ui/src/components/FileUpload/index.vue +++ b/ruoyi-ui/src/components/FileUpload/index.vue @@ -4,7 +4,7 @@ :action="uploadFileUrl" :before-upload="handleBeforeUpload" :file-list="fileList" - :limit="1" + :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed" :on-success="handleUploadSuccess" @@ -26,8 +26,8 @@ <!-- 鏂囦欢鍒楄〃 --> <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul"> - <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in list"> - <el-link :href="file.url" :underline="false" target="_blank"> + <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList"> + <el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank"> <span class="el-icon-document"> {{ getFileName(file.name) }} </span> </el-link> <div class="ele-upload-list__item-content-action"> @@ -42,9 +42,15 @@ import { getToken } from "@/utils/auth"; export default { + name: "FileUpload", props: { // 鍊� value: [String, Object, Array], + // 鏁伴噺闄愬埗 + limit: { + type: Number, + default: 5, + }, // 澶у皬闄愬埗(MB) fileSize: { type: Number, @@ -63,6 +69,7 @@ }, data() { return { + baseUrl: process.env.VUE_APP_BASE_API, uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃 headers: { Authorization: "Bearer " + getToken(), @@ -70,29 +77,34 @@ fileList: [], }; }, + watch: { + value: { + handler(val) { + if (val) { + let temp = 1; + // 棣栧厛灏嗗�艰浆涓烘暟缁� + const list = Array.isArray(val) ? val : this.value.split(','); + // 鐒跺悗灏嗘暟缁勮浆涓哄璞℃暟缁� + this.fileList = list.map(item => { + if (typeof item === "string") { + item = { name: item, url: item }; + } + item.uid = item.uid || new Date().getTime() + temp++; + return item; + }); + } else { + this.fileList = []; + return []; + } + }, + deep: true, + immediate: true + } + }, computed: { // 鏄惁鏄剧ず鎻愮ず showTip() { return this.isShowTip && (this.fileType || this.fileSize); - }, - // 鍒楄〃 - list() { - let temp = 1; - if (this.value) { - // 棣栧厛灏嗗�艰浆涓烘暟缁� - const list = Array.isArray(this.value) ? this.value : [this.value]; - // 鐒跺悗灏嗘暟缁勮浆涓哄璞℃暟缁� - return list.map((item) => { - if (typeof item === "string") { - item = { name: item, url: item }; - } - item.uid = item.uid || new Date().getTime() + temp++; - return item; - }); - } else { - this.fileList = []; - return []; - } }, }, methods: { @@ -126,7 +138,7 @@ }, // 鏂囦欢涓暟瓒呭嚭 handleExceed() { - this.$message.error(`鍙厑璁镐笂浼犲崟涓枃浠禶); + this.$message.error(`涓婁紶鏂囦欢鏁伴噺涓嶈兘瓒呰繃 ${this.limit} 涓�!`); }, // 涓婁紶澶辫触 handleUploadError(err) { @@ -135,12 +147,13 @@ // 涓婁紶鎴愬姛鍥炶皟 handleUploadSuccess(res, file) { this.$message.success("涓婁紶鎴愬姛"); - this.$emit("input", res.data.url); + this.fileList.push({ name: res.data.fileName, url: res.data.fileName }); + this.$emit("input", this.listToString(this.fileList)); }, // 鍒犻櫎鏂囦欢 handleDelete(index) { this.fileList.splice(index, 1); - this.$emit("input", ''); + this.$emit("input", this.listToString(this.fileList)); }, // 鑾峰彇鏂囦欢鍚嶇О getFileName(name) { @@ -149,11 +162,17 @@ } else { return ""; } + }, + // 瀵硅薄杞垚鎸囧畾瀛楃涓插垎闅� + listToString(list, separator) { + let strs = ""; + separator = separator || ","; + for (let i in list) { + strs += list[i].url + separator; + } + return strs != '' ? strs.substr(0, strs.length - 1) : ''; } - }, - created() { - this.fileList = this.list; - }, + } }; </script> diff --git a/ruoyi-ui/src/components/HeaderSearch/index.vue b/ruoyi-ui/src/components/HeaderSearch/index.vue index ce9f305..c44eff5 100644 --- a/ruoyi-ui/src/components/HeaderSearch/index.vue +++ b/ruoyi-ui/src/components/HeaderSearch/index.vue @@ -70,9 +70,11 @@ this.show = false }, change(val) { + const path = val.path; if(this.ishttp(val.path)) { // http(s):// 璺緞鏂扮獥鍙f墦寮� - window.open(val.path, "_blank"); + const pindex = path.indexOf("http"); + window.open(path.substr(pindex, path.length), "_blank"); } else { this.$router.push(val.path) } diff --git a/ruoyi-ui/src/components/ImageUpload/index.vue b/ruoyi-ui/src/components/ImageUpload/index.vue index 17d30d8..f2a7402 100644 --- a/ruoyi-ui/src/components/ImageUpload/index.vue +++ b/ruoyi-ui/src/components/ImageUpload/index.vue @@ -5,33 +5,38 @@ list-type="picture-card" :on-success="handleUploadSuccess" :before-upload="handleBeforeUpload" + :limit="limit" :on-error="handleUploadError" + :on-exceed="handleExceed" name="file" - :show-file-list="false" + :on-remove="handleRemove" + :show-file-list="true" :headers="headers" - style="display: inline-block; vertical-align: top" + :file-list="fileList" + :on-preview="handlePictureCardPreview" + :class="{hide: this.fileList.length >= this.limit}" > - <el-image v-if="!value" :src="value"> - <div slot="error" class="image-slot"> - <i class="el-icon-plus" /> - </div> - </el-image> - <div v-else class="image"> - <el-image :src="value" :style="`width:150px;height:150px;`" fit="fill"/> - <div class="mask"> - <div class="actions"> - <span title="棰勮" @click.stop="dialogVisible = true"> - <i class="el-icon-zoom-in" /> - </span> - <span title="绉婚櫎" @click.stop="removeImage"> - <i class="el-icon-delete" /> - </span> - </div> - </div> - </div> + <i class="el-icon-plus"></i> </el-upload> - <el-dialog :visible.sync="dialogVisible" title="棰勮" width="800" append-to-body> - <img :src="value" style="display: block; max-width: 100%; margin: 0 auto;"> + + <!-- 涓婁紶鎻愮ず --> + <div class="el-upload__tip" slot="tip" v-if="showTip"> + 璇蜂笂浼� + <template v-if="fileSize"> 澶у皬涓嶈秴杩� <b style="color: #f56c6c">{{ fileSize }}MB</b> </template> + <template v-if="fileType"> 鏍煎紡涓� <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template> + 鐨勬枃浠� + </div> + + <el-dialog + :visible.sync="dialogVisible" + title="棰勮" + width="800" + append-to-body + > + <img + :src="dialogImageUrl" + style="display: block; max-width: 100%; margin: 0 auto" + /> </el-dialog> </div> </template> @@ -40,36 +45,128 @@ import { getToken } from "@/utils/auth"; export default { + props: { + value: [String, Object, Array], + // 鍥剧墖鏁伴噺闄愬埗 + limit: { + type: Number, + default: 5, + }, + // 澶у皬闄愬埗(MB) + fileSize: { + type: Number, + default: 5, + }, + // 鏂囦欢绫诲瀷, 渚嬪['png', 'jpg', 'jpeg'] + fileType: { + type: Array, + default: () => ["png", "jpg", "jpeg"], + }, + // 鏄惁鏄剧ず鎻愮ず + isShowTip: { + type: Boolean, + default: true + } + }, data() { return { + dialogImageUrl: "", dialogVisible: false, + hideUpload: false, + baseUrl: process.env.VUE_APP_BASE_API, uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃 headers: { Authorization: "Bearer " + getToken(), }, + fileList: [] }; }, - props: { + watch: { value: { - type: String, - default: "", + handler(val) { + if (val) { + // 棣栧厛灏嗗�艰浆涓烘暟缁� + const list = Array.isArray(val) ? val : this.value.split(','); + // 鐒跺悗灏嗘暟缁勮浆涓哄璞℃暟缁� + this.fileList = list.map(item => { + if (typeof item === "string") { + if (item.indexOf(this.baseUrl) === -1) { + item = { name: this.baseUrl + item, url: this.baseUrl + item }; + } else { + item = { name: item, url: item }; + } + } + return item; + }); + } else { + this.fileList = []; + return []; + } + }, + deep: true, + immediate: true + } + }, + computed: { + // 鏄惁鏄剧ず鎻愮ず + showTip() { + return this.isShowTip && (this.fileType || this.fileSize); }, }, methods: { - removeImage() { - this.$emit("input", ""); + // 鍒犻櫎鍥剧墖 + handleRemove(file, fileList) { + const findex = this.fileList.indexOf(file.name); + this.fileList.splice(findex, 1); + this.$emit("input", this.listToString(this.fileList)); }, + // 涓婁紶鎴愬姛鍥炶皟 handleUploadSuccess(res) { - this.$emit("input", res.data.url); + this.fileList.push({ name: res.data.fileName, url: res.data.fileName }); + this.$emit("input", this.listToString(this.fileList)); this.loading.close(); }, - handleBeforeUpload() { + // 涓婁紶鍓峫oading鍔犺浇 + handleBeforeUpload(file) { + let isImg = false; + if (this.fileType.length) { + let fileExtension = ""; + if (file.name.lastIndexOf(".") > -1) { + fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1); + } + isImg = this.fileType.some(type => { + if (file.type.indexOf(type) > -1) return true; + if (fileExtension && fileExtension.indexOf(type) > -1) return true; + return false; + }); + } else { + isImg = file.type.indexOf("image") > -1; + } + + if (!isImg) { + this.$message.error( + `鏂囦欢鏍煎紡涓嶆纭�, 璇蜂笂浼�${this.fileType.join("/")}鍥剧墖鏍煎紡鏂囦欢!` + ); + return false; + } + if (this.fileSize) { + const isLt = file.size / 1024 / 1024 < this.fileSize; + if (!isLt) { + this.$message.error(`涓婁紶澶村儚鍥剧墖澶у皬涓嶈兘瓒呰繃 ${this.fileSize} MB!`); + return false; + } + } this.loading = this.$loading({ lock: true, text: "涓婁紶涓�", background: "rgba(0, 0, 0, 0.7)", }); }, + // 鏂囦欢涓暟瓒呭嚭 + handleExceed() { + this.$message.error(`涓婁紶鏂囦欢鏁伴噺涓嶈兘瓒呰繃 ${this.limit} 涓�!`); + }, + // 涓婁紶澶辫触 handleUploadError() { this.$message({ type: "error", @@ -77,24 +174,37 @@ }); this.loading.close(); }, - }, - watch: {}, + // 棰勮 + handlePictureCardPreview(file) { + this.dialogImageUrl = file.url; + this.dialogVisible = true; + }, + // 瀵硅薄杞垚鎸囧畾瀛楃涓插垎闅� + listToString(list, separator) { + let strs = ""; + separator = separator || ","; + for (let i in list) { + strs += list[i].url + separator; + } + return strs != '' ? strs.substr(0, strs.length - 1) : ''; + } + } }; </script> - <style scoped lang="scss"> -.image { - position: relative; - .mask { +// .el-upload--picture-card 鎺у埗鍔犲彿閮ㄥ垎 +::v-deep.hide .el-upload--picture-card { + display: none; +} +// 鍘绘帀鍔ㄧ敾鏁堟灉 +::v-deep .el-list-enter-active, +::v-deep .el-list-leave-active { + transition: all 0s; +} + +::v-deep .el-list-enter, .el-list-leave-active { opacity: 0; - position: absolute; - top: 0; - width: 100%; - background-color: rgba(0, 0, 0, 0.5); - transition: all 0.3s; - } - &:hover .mask { - opacity: 1; - } + transform: translateY(0); } </style> + diff --git a/ruoyi-ui/src/components/TopNav/index.vue b/ruoyi-ui/src/components/TopNav/index.vue index d89930a..c8837f2 100644 --- a/ruoyi-ui/src/components/TopNav/index.vue +++ b/ruoyi-ui/src/components/TopNav/index.vue @@ -73,9 +73,9 @@ if(router.path === "/") { router.children[item].path = "/redirect/" + router.children[item].path; } else { - if(!this.ishttp(router.children[item].path)) { + if(!this.ishttp(router.children[item].path)) { router.children[item].path = router.path + "/" + router.children[item].path; - } + } } router.children[item].parentPath = router.path; } diff --git a/ruoyi-ui/src/directive/dialog/drag.js b/ruoyi-ui/src/directive/dialog/drag.js new file mode 100644 index 0000000..728f49d --- /dev/null +++ b/ruoyi-ui/src/directive/dialog/drag.js @@ -0,0 +1,64 @@ +/** +* v-dialogDrag 寮圭獥鎷栨嫿 +* Copyright (c) 2019 ruoyi +*/ + +export default { + bind(el, binding, vnode, oldVnode) { + const value = binding.value + if (value == false) return + // 鑾峰彇鎷栨嫿鍐呭澶撮儴 + const dialogHeaderEl = el.querySelector('.el-dialog__header'); + const dragDom = el.querySelector('.el-dialog'); + dialogHeaderEl.style.cursor = 'move'; + // 鑾峰彇鍘熸湁灞炴�� ie dom鍏冪礌.currentStyle 鐏嫄璋锋瓕 window.getComputedStyle(dom鍏冪礌, null); + const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null); + dragDom.style.position = 'absolute'; + dragDom.style.marginTop = 0; + let width = dragDom.style.width; + if (width.includes('%')) { + width = +document.body.clientWidth * (+width.replace(/\%/g, '') / 100); + } else { + width = +width.replace(/\px/g, ''); + } + dragDom.style.left = `${(document.body.clientWidth - width) / 2}px`; + // 榧犳爣鎸変笅浜嬩欢 + dialogHeaderEl.onmousedown = (e) => { + // 榧犳爣鎸変笅锛岃绠楀綋鍓嶅厓绱犺窛绂诲彲瑙嗗尯鐨勮窛绂� (榧犳爣鐐瑰嚮浣嶇疆璺濈鍙绐楀彛鐨勮窛绂�) + const disX = e.clientX - dialogHeaderEl.offsetLeft; + const disY = e.clientY - dialogHeaderEl.offsetTop; + + // 鑾峰彇鍒扮殑鍊煎甫px 姝e垯鍖归厤鏇挎崲 + let styL, styT; + + // 娉ㄦ剰鍦╥e涓� 绗竴娆¤幏鍙栧埌鐨勫�间负缁勪欢鑷甫50% 绉诲姩涔嬪悗璧嬪�间负px + if (sty.left.includes('%')) { + styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100); + styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100); + } else { + styL = +sty.left.replace(/\px/g, ''); + styT = +sty.top.replace(/\px/g, ''); + }; + + // 榧犳爣鎷栨嫿浜嬩欢 + document.onmousemove = function (e) { + // 閫氳繃浜嬩欢濮旀墭锛岃绠楃Щ鍔ㄧ殑璺濈 锛堝紑濮嬫嫋鎷借嚦缁撴潫鎷栨嫿鐨勮窛绂伙級 + const l = e.clientX - disX; + const t = e.clientY - disY; + + let finallyL = l + styL + let finallyT = t + styT + + // 绉诲姩褰撳墠鍏冪礌 + dragDom.style.left = `${finallyL}px`; + dragDom.style.top = `${finallyT}px`; + + }; + + document.onmouseup = function (e) { + document.onmousemove = null; + document.onmouseup = null; + }; + } + } +}; \ No newline at end of file diff --git a/ruoyi-ui/src/directive/index.js b/ruoyi-ui/src/directive/index.js new file mode 100644 index 0000000..550109b --- /dev/null +++ b/ruoyi-ui/src/directive/index.js @@ -0,0 +1,18 @@ +import hasRole from './permission/hasRole' +import hasPermi from './permission/hasPermi' +import dialogDrag from './dialog/drag' + +const install = function(Vue) { + Vue.directive('hasRole', hasRole) + Vue.directive('hasPermi', hasPermi) + Vue.directive('dialogDrag', dialogDrag) +} + +if (window.Vue) { + window['hasRole'] = hasRole + window['hasPermi'] = hasPermi + window['dialogDrag'] = dialogDrag + Vue.use(install); // eslint-disable-line +} + +export default install diff --git a/ruoyi-ui/src/directive/permission/hasPermi.js b/ruoyi-ui/src/directive/permission/hasPermi.js index d7107ce..7101e3e 100644 --- a/ruoyi-ui/src/directive/permission/hasPermi.js +++ b/ruoyi-ui/src/directive/permission/hasPermi.js @@ -1,8 +1,8 @@ /** - * 鎿嶄綔鏉冮檺澶勭悊 + * v-hasPermi 鎿嶄綔鏉冮檺澶勭悊 * Copyright (c) 2019 ruoyi */ - + import store from '@/store' export default { diff --git a/ruoyi-ui/src/directive/permission/hasRole.js b/ruoyi-ui/src/directive/permission/hasRole.js index 1303809..ad9d4d7 100644 --- a/ruoyi-ui/src/directive/permission/hasRole.js +++ b/ruoyi-ui/src/directive/permission/hasRole.js @@ -1,8 +1,8 @@ /** - * 瑙掕壊鏉冮檺澶勭悊 + * v-hasRole 瑙掕壊鏉冮檺澶勭悊 * Copyright (c) 2019 ruoyi */ - + import store from '@/store' export default { diff --git a/ruoyi-ui/src/directive/permission/index.js b/ruoyi-ui/src/directive/permission/index.js deleted file mode 100644 index e3d76d3..0000000 --- a/ruoyi-ui/src/directive/permission/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import hasRole from './hasRole' -import hasPermi from './hasPermi' - -const install = function(Vue) { - Vue.directive('hasRole', hasRole) - Vue.directive('hasPermi', hasPermi) -} - -if (window.Vue) { - window['hasRole'] = hasRole - window['hasPermi'] = hasPermi - Vue.use(install); // eslint-disable-line -} - -export default install diff --git a/ruoyi-ui/src/layout/components/AppMain.vue b/ruoyi-ui/src/layout/components/AppMain.vue index a897638..0c6f4b7 100644 --- a/ruoyi-ui/src/layout/components/AppMain.vue +++ b/ruoyi-ui/src/layout/components/AppMain.vue @@ -51,7 +51,7 @@ // fix css style bug in open el-dialog .el-popup-parent--hidden { .fixed-header { - padding-right: 15px; + padding-right: 17px; } } </style> diff --git a/ruoyi-ui/src/layout/components/InnerLink/index.vue b/ruoyi-ui/src/layout/components/InnerLink/index.vue new file mode 100644 index 0000000..227ff2a --- /dev/null +++ b/ruoyi-ui/src/layout/components/InnerLink/index.vue @@ -0,0 +1,27 @@ +<script> +export default { + data() { + return {}; + }, + render() { + const { $route: { meta: { link } }, } = this; + if ({ link }.link === "") { + return "404"; + } + let url = { link }.link; + const height = document.documentElement.clientHeight - 94.5 + "px"; + const style = { height: height }; + + return ( + <div style={style}> + <iframe + src={url} + frameborder="no" + style="width: 100%; height: 100%" + scrolling="auto" + ></iframe> + </div> + ); + }, +}; +</script> diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js index d1f8973..d07dead 100644 --- a/ruoyi-ui/src/main.js +++ b/ruoyi-ui/src/main.js @@ -10,7 +10,7 @@ import App from './App' import store from './store' import router from './router' -import permission from './directive/permission' +import directive from './directive' //directive import './assets/icons' // icon import './permission' // permission control @@ -20,6 +20,12 @@ import Pagination from "@/components/Pagination"; // 鑷畾涔夎〃鏍煎伐鍏风粍浠� import RightToolbar from "@/components/RightToolbar" +// 瀵屾枃鏈粍浠� +import Editor from "@/components/Editor" +// 鏂囦欢涓婁紶缁勪欢 +import FileUpload from "@/components/FileUpload" +// 鍥剧墖涓婁紶缁勪欢 +import ImageUpload from "@/components/ImageUpload" // 瀛楀吀鏍囩缁勪欢 import DictTag from '@/components/DictTag' // 澶撮儴鏍囩缁勪欢 @@ -52,8 +58,11 @@ Vue.component('DictTag', DictTag) Vue.component('Pagination', Pagination) Vue.component('RightToolbar', RightToolbar) +Vue.component('Editor', Editor) +Vue.component('FileUpload', FileUpload) +Vue.component('ImageUpload', ImageUpload) -Vue.use(permission) +Vue.use(directive) Vue.use(VueMeta) /** diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js index ffb12e7..c7b9371 100644 --- a/ruoyi-ui/src/router/index.js +++ b/ruoyi-ui/src/router/index.js @@ -6,6 +6,7 @@ /* Layout */ import Layout from '@/layout' import ParentView from '@/components/ParentView'; +import InnerLink from '@/layout/components/InnerLink' /** * Note: 璺敱閰嶇疆椤� @@ -81,6 +82,32 @@ ] }, { + path: '/auth', + component: Layout, + hidden: true, + children: [ + { + path: 'role/:userId(\\d+)', + component: (resolve) => require(['@/views/system/user/authRole'], resolve), + name: 'AuthRole', + meta: { title: '鍒嗛厤瑙掕壊'} + } + ] + }, + { + path: '/auth', + component: Layout, + hidden: true, + children: [ + { + path: 'user/:roleId(\\d+)', + component: (resolve) => require(['@/views/system/role/authUser'], resolve), + name: 'AuthUser', + meta: { title: '鍒嗛厤鐢ㄦ埛'} + } + ] + }, + { path: '/dict', component: Layout, hidden: true, diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js index aacfc8c..81026f3 100644 --- a/ruoyi-ui/src/store/modules/permission.js +++ b/ruoyi-ui/src/store/modules/permission.js @@ -2,6 +2,7 @@ import { getRouters } from '@/api/menu' import Layout from '@/layout/index' import ParentView from '@/components/ParentView'; +import InnerLink from '@/layout/components/InnerLink' const permission = { state: { @@ -65,6 +66,8 @@ route.component = Layout } else if (route.component === 'ParentView') { route.component = ParentView + } else if (route.component === 'InnerLink') { + route.component = InnerLink } else { route.component = loadView(route.component) } diff --git a/ruoyi-ui/src/views/demo/demo/index.vue b/ruoyi-ui/src/views/demo/demo/index.vue index 279c469..a6679f3 100644 --- a/ruoyi-ui/src/views/demo/demo/index.vue +++ b/ruoyi-ui/src/views/demo/demo/index.vue @@ -304,17 +304,19 @@ this.buttonLoading = true; if (this.form.id != null) { updateDemo(this.form).then(response => { - this.buttonLoading = false; this.msgSuccess("淇敼鎴愬姛"); this.open = false; this.getList(); + }).finally(() => { + this.buttonLoading = false; }); } else { addDemo(this.form).then(response => { - this.buttonLoading = false; this.msgSuccess("鏂板鎴愬姛"); this.open = false; this.getList(); + }).finally(() => { + this.buttonLoading = false; }); } } diff --git a/ruoyi-ui/src/views/demo/tree/index.vue b/ruoyi-ui/src/views/demo/tree/index.vue index afe96c4..57b152f 100644 --- a/ruoyi-ui/src/views/demo/tree/index.vue +++ b/ruoyi-ui/src/views/demo/tree/index.vue @@ -255,17 +255,19 @@ this.buttonLoading = true; if (this.form.id != null) { updateTree(this.form).then(response => { - this.buttonLoading = false; this.msgSuccess("淇敼鎴愬姛"); this.open = false; this.getList(); + }).finally(() => { + this.buttonLoading = false; }); } else { addTree(this.form).then(response => { - this.buttonLoading = false; this.msgSuccess("鏂板鎴愬姛"); this.open = false; this.getList(); + }).finally(() => { + this.buttonLoading = false; }); } } diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue index dba6dfe..671dcde 100644 --- a/ruoyi-ui/src/views/index.vue +++ b/ruoyi-ui/src/views/index.vue @@ -91,6 +91,32 @@ <span>鏇存柊鏃ュ織</span> </div> <el-collapse accordion> + <el-collapse-item title="v2.5.0 - 2021-7-12"> + <ol> + <li>update springboot 2.4.7 => 2.4.8</li> + <li>update knife4j 3.0.2 => 3.0.3</li> + <li>update hutool 5.7.2 => 5.7.4</li> + <li>update spring-boot-admin 2.4.1 => 2.4.3</li> + <li>update redisson 3.15.2 => 3.16.0</li> + <li>add 澧炲姞 docker 缂栨帓 涓� shell 鑴氭湰</li> + <li>add 澧炲姞 feign 鐔旀柇 鑷畾涔夌粨鏋勪綋瑙f瀽鏂规硶 涓� demo 娉ㄩ噴</li> + <li>add 鐢ㄦ埛绠$悊鏂板鍒嗛厤瑙掕壊鍔熻兘</li> + <li>add 瑙掕壊绠$悊鏂板鍒嗛厤鐢ㄦ埛鍔熻兘</li> + <li>add 澧炲姞spring-cache婕旂ず妗堜緥</li> + <li>update 鐙珛 springboot-admin 鐩戞帶鍒版墿灞曟ā鍧楅」鐩�</li> + <li>update springboot-admin 鐩戞帶 澧炲姞鐢ㄦ埛鐧诲綍鏉冮檺绠$悊</li> + <li>update 浼樺寲浠g爜鐢熸垚鍣� 鎵归噺瀵煎叆</li> + <li>update 浼樺寲 澧炲姞MP娉ㄥ叆寮傚父鎷︽埅</li> + <li>update 鍏抽棴榛樿浜岀骇缂撳瓨 鎺ㄨ崘浣跨敤 spring-cache 娉ㄨВ鎵嬪姩缂撳瓨</li> + <li>update FileUpload ImageUpload缁勪欢 鏀寔澶氬浘鐗囦笂浼�</li> + <li>update 浼樺寲涓嫳鏂囪瑷�閰嶇疆</li> + <li>update 瑙勮寖maven鍐欐硶</li> + <li>fix redis鑾峰彇map灞炴�ug淇銆�</li> + <li>fix 淇 鎸夐挳loading 鍚庣500鍗℃闂</li> + <li>fix 鐩稿璺緞涓嬭浇闂</li> + <li>fix 淇 hutool 宸ュ叿杩斿洖缁撴灉涓嶄竴鑷撮棶棰�</li> + </ol> + </el-collapse-item> <el-collapse-item title="v2.4.0 - 2021-6-24"> <ol> <li>update springboot 2.3.11 => 2.4.7</li> diff --git a/ruoyi-ui/src/views/monitor/admin/index.vue b/ruoyi-ui/src/views/monitor/admin/index.vue index f1d48b0..ad35dc4 100644 --- a/ruoyi-ui/src/views/monitor/admin/index.vue +++ b/ruoyi-ui/src/views/monitor/admin/index.vue @@ -1,26 +1,16 @@ <template> - <div v-loading="loading" :style="'height:'+ height"> - <iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" /> - </div> + <i-frame :src="url" /> </template> <script> +import iFrame from "@/components/iFrame/index"; export default { name: "Admin", + components: { iFrame }, data() { + console.log(process.env) return { - src: process.env.VUE_APP_BASE_API + "/admin", - height: document.documentElement.clientHeight - 94.5 + "px;", - loading: true + url: process.env.VUE_APP_MONITRO_ADMIN }; }, - mounted: function() { - setTimeout(() => { - this.loading = false; - }, 230); - const that = this; - window.onresize = function temp() { - that.height = document.documentElement.clientHeight - 94.5 + "px;"; - }; - } }; </script> diff --git a/ruoyi-ui/src/views/system/notice/index.vue b/ruoyi-ui/src/views/system/notice/index.vue index 3115543..0ffd9d6 100644 --- a/ruoyi-ui/src/views/system/notice/index.vue +++ b/ruoyi-ui/src/views/system/notice/index.vue @@ -177,13 +177,9 @@ <script> import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice"; -import Editor from '@/components/Editor'; export default { name: "Notice", - components: { - Editor - }, data() { return { // 閬僵灞� diff --git a/ruoyi-ui/src/views/system/role/authUser.vue b/ruoyi-ui/src/views/system/role/authUser.vue new file mode 100644 index 0000000..a65ccbf --- /dev/null +++ b/ruoyi-ui/src/views/system/role/authUser.vue @@ -0,0 +1,213 @@ +<template> + <div class="app-container"> + <el-form :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true"> + <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userName"> + <el-input + v-model="queryParams.userName" + placeholder="璇疯緭鍏ョ敤鎴峰悕绉�" + clearable + size="small" + style="width: 240px" + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber"> + <el-input + v-model="queryParams.phonenumber" + placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" + clearable + size="small" + style="width: 240px" + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item> + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button> + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button> + </el-form-item> + </el-form> + + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button + type="primary" + plain + icon="el-icon-plus" + size="mini" + @click="openSelectUser" + v-hasPermi="['system:role:add']" + >娣诲姞鐢ㄦ埛</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="danger" + plain + icon="el-icon-circle-close" + size="mini" + :disabled="multiple" + @click="cancelAuthUserAll" + v-hasPermi="['system:role:remove']" + >鎵归噺鍙栨秷鎺堟潈</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="warning" + plain + icon="el-icon-close" + size="mini" + @click="handleClose" + >鍏抽棴</el-button> + </el-col> + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> + </el-row> + + <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> + <el-table-column type="selection" width="55" align="center" /> + <el-table-column label="鐢ㄦ埛鍚嶇О" prop="userName" :show-overflow-tooltip="true" /> + <el-table-column label="鐢ㄦ埛鏄电О" prop="nickName" :show-overflow-tooltip="true" /> + <el-table-column label="閭" prop="email" :show-overflow-tooltip="true" /> + <el-table-column label="鎵嬫満" prop="phonenumber" :show-overflow-tooltip="true" /> + <el-table-column label="鐘舵��" align="center" prop="status"> + <template slot-scope="scope"> + <dict-tag :options="statusOptions" :value="scope.row.status"/> + </template> + </el-table-column> + <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180"> + <template slot-scope="scope"> + <span>{{ parseTime(scope.row.createTime) }}</span> + </template> + </el-table-column> + <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width"> + <template slot-scope="scope"> + <el-button + size="mini" + type="text" + icon="el-icon-circle-close" + @click="cancelAuthUser(scope.row)" + v-hasPermi="['system:role:remove']" + >鍙栨秷鎺堟潈</el-button> + </template> + </el-table-column> + </el-table> + + <pagination + v-show="total>0" + :total="total" + :page.sync="queryParams.pageNum" + :limit.sync="queryParams.pageSize" + @pagination="getList" + /> + <select-user ref="select" :roleId="queryParams.roleId" @ok="handleQuery" /> + </div> +</template> + +<script> +import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role"; +import selectUser from "./selectUser"; + +export default { + name: "AuthUser", + components: { selectUser }, + data() { + return { + // 閬僵灞� + loading: true, + // 閫変腑鐢ㄦ埛缁� + userIds: [], + // 闈炲涓鐢� + multiple: true, + // 鏄剧ず鎼滅储鏉′欢 + showSearch: true, + // 鎬绘潯鏁� + total: 0, + // 鐢ㄦ埛琛ㄦ牸鏁版嵁 + userList: [], + // 鐘舵�佹暟鎹瓧鍏� + statusOptions: [], + // 鏌ヨ鍙傛暟 + queryParams: { + pageNum: 1, + pageSize: 10, + roleId: undefined, + userName: undefined, + phonenumber: undefined + } + }; + }, + created() { + const roleId = this.$route.params && this.$route.params.roleId; + if (roleId) { + this.queryParams.roleId = roleId; + this.getList(); + this.getDicts("sys_normal_disable").then(response => { + this.statusOptions = response.data; + }); + } + }, + methods: { + /** 鏌ヨ鎺堟潈鐢ㄦ埛鍒楄〃 */ + getList() { + this.loading = true; + allocatedUserList(this.queryParams).then(response => { + this.userList = response.rows; + this.total = response.total; + this.loading = false; + } + ); + }, + // 杩斿洖鎸夐挳 + handleClose() { + this.$store.dispatch("tagsView/delView", this.$route); + this.$router.push({ path: "/system/role" }); + }, + /** 鎼滅储鎸夐挳鎿嶄綔 */ + handleQuery() { + this.queryParams.pageNum = 1; + this.getList(); + }, + /** 閲嶇疆鎸夐挳鎿嶄綔 */ + resetQuery() { + this.resetForm("queryForm"); + this.handleQuery(); + }, + // 澶氶�夋閫変腑鏁版嵁 + handleSelectionChange(selection) { + this.userIds = selection.map(item => item.userId) + this.multiple = !selection.length + }, + /** 鎵撳紑鎺堟潈鐢ㄦ埛琛ㄥ脊绐� */ + openSelectUser() { + this.$refs.select.show(); + }, + /** 鍙栨秷鎺堟潈鎸夐挳鎿嶄綔 */ + cancelAuthUser(row) { + const roleId = this.queryParams.roleId; + this.$confirm('纭瑕佸彇娑堣鐢ㄦ埛"' + row.userName + '"瑙掕壊鍚楋紵', "璀﹀憡", { + confirmButtonText: "纭畾", + cancelButtonText: "鍙栨秷", + type: "warning" + }).then(function() { + return authUserCancel({ userId: row.userId, roleId: roleId }); + }).then(() => { + this.getList(); + this.msgSuccess("鍙栨秷鎺堟潈鎴愬姛"); + }).catch(() => {}); + }, + /** 鎵归噺鍙栨秷鎺堟潈鎸夐挳鎿嶄綔 */ + cancelAuthUserAll(row) { + const roleId = this.queryParams.roleId; + const userIds = this.userIds.join(","); + this.$confirm('鏄惁鍙栨秷閫変腑鐢ㄦ埛鎺堟潈鏁版嵁椤�?', "璀﹀憡", { + confirmButtonText: "纭畾", + cancelButtonText: "鍙栨秷", + type: "warning" + }).then(() => { + return authUserCancelAll({ roleId: roleId, userIds: userIds }); + }).then(() => { + this.getList(); + this.msgSuccess("鍙栨秷鎺堟潈鎴愬姛"); + }).catch(() => {}); + } + } +}; +</script> \ No newline at end of file diff --git a/ruoyi-ui/src/views/system/role/index.vue b/ruoyi-ui/src/views/system/role/index.vue index 081ea81..5bedd49 100644 --- a/ruoyi-ui/src/views/system/role/index.vue +++ b/ruoyi-ui/src/views/system/role/index.vue @@ -124,7 +124,7 @@ </template> </el-table-column> <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width"> - <template slot-scope="scope"> + <template slot-scope="scope" v-if="scope.row.roleId !== 1"> <el-button size="mini" type="text" @@ -135,17 +135,21 @@ <el-button size="mini" type="text" - icon="el-icon-circle-check" - @click="handleDataScope(scope.row)" - v-hasPermi="['system:role:edit']" - >鏁版嵁鏉冮檺</el-button> - <el-button - size="mini" - type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:role:remove']" >鍒犻櫎</el-button> + <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)"> + <span class="el-dropdown-link"> + <i class="el-icon-d-arrow-right el-icon--right"></i>鏇村 + </span> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item command="handleDataScope" icon="el-icon-circle-check" + v-hasPermi="['system:role:edit']">鏁版嵁鏉冮檺</el-dropdown-item> + <el-dropdown-item command="handleAuthUser" icon="el-icon-user" + v-hasPermi="['system:role:edit']">鍒嗛厤鐢ㄦ埛</el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> </template> </el-table-column> </el-table> @@ -469,6 +473,19 @@ this.single = selection.length!=1 this.multiple = !selection.length }, + // 鏇村鎿嶄綔瑙﹀彂 + handleCommand(command, row) { + switch (command) { + case "handleDataScope": + this.handleDataScope(row); + break; + case "handleAuthUser": + this.handleAuthUser(row); + break; + default: + break; + } + }, // 鏍戞潈闄愶紙灞曞紑/鎶樺彔锛� handleCheckedTreeExpand(value, type) { if (type == 'menu') { @@ -548,6 +565,11 @@ this.title = "鍒嗛厤鏁版嵁鏉冮檺"; }); }, + /** 鍒嗛厤鐢ㄦ埛鎿嶄綔 */ + handleAuthUser: function(row) { + const roleId = row.roleId; + this.$router.push("/auth/user/" + roleId); + }, /** 鎻愪氦鎸夐挳 */ submitForm: function() { this.$refs["form"].validate(valid => { diff --git a/ruoyi-ui/src/views/system/role/selectUser.vue b/ruoyi-ui/src/views/system/role/selectUser.vue new file mode 100644 index 0000000..14ae0bb --- /dev/null +++ b/ruoyi-ui/src/views/system/role/selectUser.vue @@ -0,0 +1,142 @@ +<template> + <!-- 鎺堟潈鐢ㄦ埛 --> + <el-dialog title="閫夋嫨鐢ㄦ埛" :visible.sync="visible" width="800px" top="5vh" append-to-body> + <el-form :model="queryParams" ref="queryForm" :inline="true"> + <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userName"> + <el-input + v-model="queryParams.userName" + placeholder="璇疯緭鍏ョ敤鎴峰悕绉�" + clearable + size="small" + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber"> + <el-input + v-model="queryParams.phonenumber" + placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" + clearable + size="small" + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item> + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button> + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button> + </el-form-item> + </el-form> + <el-row> + <el-table @row-click="clickRow" ref="table" :data="userList" @selection-change="handleSelectionChange" height="260px"> + <el-table-column type="selection" width="55"></el-table-column> + <el-table-column label="鐢ㄦ埛鍚嶇О" prop="userName" :show-overflow-tooltip="true" /> + <el-table-column label="鐢ㄦ埛鏄电О" prop="nickName" :show-overflow-tooltip="true" /> + <el-table-column label="閭" prop="email" :show-overflow-tooltip="true" /> + <el-table-column label="鎵嬫満" prop="phonenumber" :show-overflow-tooltip="true" /> + <el-table-column label="鐘舵��" align="center" prop="status"> + <template slot-scope="scope"> + <dict-tag :options="statusOptions" :value="scope.row.status"/> + </template> + </el-table-column> + <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180"> + <template slot-scope="scope"> + <span>{{ parseTime(scope.row.createTime) }}</span> + </template> + </el-table-column> + </el-table> + <pagination + v-show="total>0" + :total="total" + :page.sync="queryParams.pageNum" + :limit.sync="queryParams.pageSize" + @pagination="getList" + /> + </el-row> + <div slot="footer" class="dialog-footer"> + <el-button type="primary" @click="handleSelectUser">纭� 瀹�</el-button> + <el-button @click="visible = false">鍙� 娑�</el-button> + </div> + </el-dialog> +</template> + +<script> +import { unallocatedUserList, authUserSelectAll } from "@/api/system/role"; +export default { + props: { + // 瑙掕壊缂栧彿 + roleId: { + type: Number + } + }, + data() { + return { + // 閬僵灞� + visible: false, + // 閫変腑鏁扮粍鍊� + userIds: [], + // 鎬绘潯鏁� + total: 0, + // 鏈巿鏉冪敤鎴锋暟鎹� + userList: [], + // 鐘舵�佹暟鎹瓧鍏� + statusOptions: [], + // 鏌ヨ鍙傛暟 + queryParams: { + pageNum: 1, + pageSize: 10, + roleId: undefined, + userName: undefined, + phonenumber: undefined + } + }; + }, + created() { + this.getDicts("sys_normal_disable").then(response => { + this.statusOptions = response.data; + }); + }, + methods: { + // 鏄剧ず寮规 + show() { + this.queryParams.roleId = this.roleId; + this.getList(); + this.visible = true; + }, + clickRow(row) { + this.$refs.table.toggleRowSelection(row); + }, + // 澶氶�夋閫変腑鏁版嵁 + handleSelectionChange(selection) { + this.userIds = selection.map(item => item.userId); + }, + // 鏌ヨ琛ㄦ暟鎹� + getList() { + unallocatedUserList(this.queryParams).then(res => { + this.userList = res.rows; + this.total = res.total; + }); + }, + /** 鎼滅储鎸夐挳鎿嶄綔 */ + handleQuery() { + this.queryParams.pageNum = 1; + this.getList(); + }, + /** 閲嶇疆鎸夐挳鎿嶄綔 */ + resetQuery() { + this.resetForm("queryForm"); + this.handleQuery(); + }, + /** 閫夋嫨鎺堟潈鐢ㄦ埛鎿嶄綔 */ + handleSelectUser() { + const roleId = this.queryParams.roleId; + const userIds = this.userIds.join(","); + authUserSelectAll({ roleId: roleId, userIds: userIds }).then(res => { + this.msgSuccess(res.msg); + if (res.code === 200) { + this.visible = false; + this.$emit("ok"); + } + }); + } + } +}; +</script> diff --git a/ruoyi-ui/src/views/system/user/authRole.vue b/ruoyi-ui/src/views/system/user/authRole.vue new file mode 100644 index 0000000..8e7f82a --- /dev/null +++ b/ruoyi-ui/src/views/system/user/authRole.vue @@ -0,0 +1,117 @@ +<template> + <div class="app-container"> + <h4 class="form-header h4">鍩烘湰淇℃伅</h4> + <el-form ref="form" :model="form" label-width="80px"> + <el-row> + <el-col :span="8" :offset="2"> + <el-form-item label="鐢ㄦ埛鏄电О" prop="nickName"> + <el-input v-model="form.nickName" disabled /> + </el-form-item> + </el-col> + <el-col :span="8" :offset="2"> + <el-form-item label="鐧诲綍璐﹀彿" prop="phonenumber"> + <el-input v-model="form.userName" disabled /> + </el-form-item> + </el-col> + </el-row> + </el-form> + + <h4 class="form-header h4">瑙掕壊淇℃伅</h4> + <el-table v-loading="loading" :row-key="getRowKey" @row-click="clickRow" ref="table" @selection-change="handleSelectionChange" :data="roles.slice((pageNum-1)*pageSize,pageNum*pageSize)"> + <el-table-column label="搴忓彿" type="index" align="center"> + <template slot-scope="scope"> + <span>{{(pageNum - 1) * pageSize + scope.$index + 1}}</span> + </template> + </el-table-column> + <el-table-column type="selection" :reserve-selection="true" width="55"></el-table-column> + <el-table-column label="瑙掕壊缂栧彿" align="center" prop="roleId" /> + <el-table-column label="瑙掕壊鍚嶇О" align="center" prop="roleName" /> + <el-table-column label="鏉冮檺瀛楃" align="center" prop="roleKey" /> + <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180"> + <template slot-scope="scope"> + <span>{{ parseTime(scope.row.createTime) }}</span> + </template> + </el-table-column> + </el-table> + + <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" /> + + <el-form label-width="100px"> + <el-form-item style="text-align: center;margin-left:-120px;margin-top:30px;"> + <el-button type="primary" @click="submitForm()">鎻愪氦</el-button> + <el-button @click="close()">杩斿洖</el-button> + </el-form-item> + </el-form> + </div> +</template> + +<script> +import { getAuthRole, updateAuthRole } from "@/api/system/user"; + +export default { + name: "AuthRole", + data() { + return { + // 閬僵灞� + loading: true, + // 鍒嗛〉淇℃伅 + total: 0, + pageNum: 1, + pageSize: 10, + // 閫変腑瑙掕壊缂栧彿 + roleIds:[], + // 瑙掕壊淇℃伅 + roles: [], + // 鐢ㄦ埛淇℃伅 + form: {} + }; + }, + created() { + const userId = this.$route.params && this.$route.params.userId; + if (userId) { + this.loading = true; + getAuthRole(userId).then((response) => { + this.form = response.data.user; + this.roles = response.data.roles; + this.total = this.roles.length; + this.$nextTick(() => { + this.roles.forEach((row) => { + if (row.flag) { + this.$refs.table.toggleRowSelection(row); + } + }); + }); + this.loading = false; + }); + } + }, + methods: { + /** 鍗曞嚮閫変腑琛屾暟鎹� */ + clickRow(row) { + this.$refs.table.toggleRowSelection(row); + }, + // 澶氶�夋閫変腑鏁版嵁 + handleSelectionChange(selection) { + this.roleIds = selection.map((item) => item.roleId); + }, + // 淇濆瓨閫変腑鐨勬暟鎹紪鍙� + getRowKey(row) { + return row.roleId; + }, + /** 鎻愪氦鎸夐挳 */ + submitForm() { + const userId = this.form.userId; + const roleIds = this.roleIds.join(","); + updateAuthRole({ userId: userId, roleIds: roleIds }).then((response) => { + this.msgSuccess("鎺堟潈鎴愬姛"); + this.close(); + }); + }, + /** 鍏抽棴鎸夐挳 */ + close() { + this.$store.dispatch("tagsView/delView", this.$route); + this.$router.push({ path: "/system/user" }); + }, + }, +}; +</script> diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue index 471e66f..605cf6e 100644 --- a/ruoyi-ui/src/views/system/user/index.vue +++ b/ruoyi-ui/src/views/system/user/index.vue @@ -167,7 +167,7 @@ width="160" class-name="small-padding fixed-width" > - <template slot-scope="scope"> + <template slot-scope="scope" v-if="scope.row.userId !== 1"> <el-button size="mini" type="text" @@ -176,20 +176,23 @@ v-hasPermi="['system:user:edit']" >淇敼</el-button> <el-button - v-if="scope.row.userId !== 1" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']" >鍒犻櫎</el-button> - <el-button - size="mini" - type="text" - icon="el-icon-key" - @click="handleResetPwd(scope.row)" - v-hasPermi="['system:user:resetPwd']" - >閲嶇疆</el-button> + <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)"> + <span class="el-dropdown-link"> + <i class="el-icon-d-arrow-right el-icon--right"></i>鏇村 + </span> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item command="handleResetPwd" icon="el-icon-key" + v-hasPermi="['system:user:resetPwd']">閲嶇疆瀵嗙爜</el-dropdown-item> + <el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check" + v-hasPermi="['system:user:edit']">鍒嗛厤瑙掕壊</el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> </template> </el-table-column> </el-table> @@ -561,6 +564,19 @@ this.single = selection.length != 1; this.multiple = !selection.length; }, + // 鏇村鎿嶄綔瑙﹀彂 + handleCommand(command, row) { + switch (command) { + case "handleResetPwd": + this.handleResetPwd(row); + break; + case "handleAuthRole": + this.handleAuthRole(row); + break; + default: + break; + } + }, /** 鏂板鎸夐挳鎿嶄綔 */ handleAdd() { this.reset(); @@ -603,6 +619,11 @@ }); }).catch(() => {}); }, + /** 鍒嗛厤瑙掕壊鎿嶄綔 */ + handleAuthRole: function(row) { + const userId = row.userId; + this.$router.push("/auth/role/" + userId); + }, /** 鎻愪氦鎸夐挳 */ submitForm: function() { this.$refs["form"].validate(valid => { diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js index c749c8c..ee6353c 100644 --- a/ruoyi-ui/vue.config.js +++ b/ruoyi-ui/vue.config.js @@ -109,7 +109,7 @@ config.optimization.runtimeChunk('single'), { from: path.resolve(__dirname, './public/robots.txt'), //闃茬埇铏枃浠� - to: './', //鍒版牴鐩綍涓� + to: './' //鍒版牴鐩綍涓� } } ) diff --git a/sql/ry_20210210.sql b/sql/ry_20210210.sql index 1d8ec36..59a55f1 100644 --- a/sql/ry_20210210.sql +++ b/sql/ry_20210210.sql @@ -159,7 +159,7 @@ insert into sys_menu values('1', '绯荤粺绠$悊', '0', '1', 'system', null, 1, 0, 'M', '0', '0', '', 'system', 'admin', sysdate(), '', null, '绯荤粺绠$悊鐩綍'); insert into sys_menu values('2', '绯荤粺鐩戞帶', '0', '2', 'monitor', null, 1, 0, 'M', '0', '0', '', 'monitor', 'admin', sysdate(), '', null, '绯荤粺鐩戞帶鐩綍'); insert into sys_menu values('3', '绯荤粺宸ュ叿', '0', '3', 'tool', null, 1, 0, 'M', '0', '0', '', 'tool', 'admin', sysdate(), '', null, '绯荤粺宸ュ叿鐩綍'); -insert into sys_menu values('4', '鑻ヤ緷瀹樼綉', '0', '4', 'http://ruoyi.vip', null , 0, 0, 'M', '0', '0', '', 'guide', 'admin', sysdate(), '', null, '鑻ヤ緷瀹樼綉鍦板潃'); +insert into sys_menu values('4', 'PLUS瀹樼綉', '0', '4', 'https://gitee.com/JavaLionLi/RuoYi-Vue-Plus', null , 0, 0, 'M', '0', '0', '', 'guide', 'admin', sysdate(), '', null, 'RuoYi-Vue-Plus瀹樼綉鍦板潃'); -- 浜岀骇鑿滃崟 insert into sys_menu values('100', '鐢ㄦ埛绠$悊', '1', '1', 'user', 'system/user/index', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', sysdate(), '', null, '鐢ㄦ埛绠$悊鑿滃崟'); insert into sys_menu values('101', '瑙掕壊绠$悊', '1', '2', 'role', 'system/role/index', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', sysdate(), '', null, '瑙掕壊绠$悊鑿滃崟'); @@ -685,4 +685,4 @@ update_by varchar(64) default '' comment '鏇存柊鑰�', update_time datetime comment '鏇存柊鏃堕棿', primary key (column_id) -) engine=innodb auto_increment=1 comment = '浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�'; \ No newline at end of file +) engine=innodb auto_increment=1 comment = '浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�'; -- Gitblit v1.9.3